├── DIRS
├── INSTALL.BAT
├── INSTALLC.BAT
├── README.md
├── RFC3347.TXT
├── RFC3720.pdf
├── RFC3783.TXT
├── RFC5048.TXT
├── uSCSI
├── IoCtl.c
├── MAKEFILE
├── Pnp.c
├── Public.h
├── ReadWrite.c
├── SOURCES
├── USCSI.INF
├── Utils.c
├── precomp.h
├── srb.c
├── uSCSI.c
└── uSCSI.h
├── uSCSIPort
├── Cmd.c
├── Data.c
├── Discover.c
├── Handler.c
├── Key.c
├── Login.c
├── Nop.c
├── ProtUtils.c
├── Protocol.c
├── Protocol.h
├── R2T.c
├── Reject.c
├── Response.c
├── SNACK.c
├── SOURCES
├── Task.c
├── Text.c
├── TransUtils.c
├── Transport.c
├── Transport.h
├── precomp.h
├── uSCSI.c
├── uSCSI.h
├── uSCSIPort.def
├── uSCSIPort.h
└── uSCSIPortPublic.h
└── uSCSI设计文档.pdf
/DIRS:
--------------------------------------------------------------------------------
1 | DIRS=uSCSIPort uSCSI
--------------------------------------------------------------------------------
/INSTALL.BAT:
--------------------------------------------------------------------------------
1 | cd C:\src\DrvDev\uSCSI\objfre_wxp_x86\i386
2 | copy C:\src\DrvDev\uSCSI\uscsi.inf .
3 | devcon install uscsi.inf uSCSI\uSCSI
4 | cd C:\src\DrvDev\uSCSI
--------------------------------------------------------------------------------
/INSTALLC.BAT:
--------------------------------------------------------------------------------
1 | cd C:\src\DrvDev\uSCSI\objchk_wxp_x86\i386
2 | copy C:\src\DrvDev\uSCSI\uscsi.inf .
3 | devcon install uscsi.inf uSCSI\uSCSI
4 | cd C:\src\DrvDev\uSCSI
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # iSCSI_drv
2 | an iSCSI demo driver for Windows XP
3 |
4 | 1. components
5 | -------------
6 |
7 | component | description |
8 | uSCSIPort.sys | iSCSI protocol lib |
9 | uSCSI.sys | disk driver |
10 | uscsi.inf | inf file |
11 | devcon | driver tools |
12 | uscsictl | command line tools , use to add target , connect initiator to target etc. |
13 |
14 |
15 | 2. installation
16 | -------------
17 | 1. copy uSCSIPort.sys to system32/drivers
18 | 1. install disk driver
19 |
20 | **devcon install uscsi.inf uSCSI\uSCSI**
21 |
22 | 1. setup StarWind with target name iqn.com.yushang:vdisk.01
23 | 1. add target
24 |
25 | **uscsictl -t iqn.com.yushang:vdisk.01 192.168.1.123**
26 |
27 | 1. connect to target
28 |
29 | **uscsictl -c iqn.com.yushang:vdisk.01**
30 |
31 | 1. initialize disk use Windows disk management MMC
32 |
33 | 3. performance metrics
34 | ----------------------
35 | on MS VPC , test with HD Tune
36 | * READ:
37 | * min 2.8 m/s
38 | * avg 15.2 m/s
39 | * max 20.1 m/s
40 | * access time 11.1 ms
41 | * burst rate 19.2 m/s
42 | * CPU usage 14.3%
43 |
44 | 4. reference
45 | ------------
46 | please refer uSCSI设计文档.pdf(Chinese) for details
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/RFC3720.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldoldman/iSCSI_drv/e118622fa43c4756038bc72a2ef4492f807a10f8/RFC3720.pdf
--------------------------------------------------------------------------------
/RFC3783.TXT:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Network Working Group M. Chadalapaka
8 | Request for Comments: 3783 R. Elliott
9 | Category: Informational Hewlett-Packard Co.
10 | May 2004
11 |
12 |
13 | Small Computer Systems Interface (SCSI)
14 | Command Ordering Considerations with iSCSI
15 |
16 | Status of this Memo
17 |
18 | This memo provides information for the Internet community. It does
19 | not specify an Internet standard of any kind. Distribution of this
20 | memo is unlimited.
21 |
22 | Copyright Notice
23 |
24 | Copyright (C) The Internet Society (2004). All Rights Reserved.
25 |
26 | Abstract
27 |
28 | Internet Small Computer Systems Interface (iSCSI) is a Small Computer
29 | Systems Interface (SCSI) transport protocol designed to run on top of
30 | TCP. The iSCSI session abstraction is equivalent to the classic SCSI
31 | "I_T nexus", which represents the logical relationship between an
32 | Initiator and a Target (I and T) required in order to communicate via
33 | the SCSI family of protocols. The iSCSI session provides an ordered
34 | command delivery from the SCSI initiator to the SCSI target. This
35 | document goes into the design considerations that led to the iSCSI
36 | session model as it is defined today, relates the SCSI command
37 | ordering features defined in T10 specifications to the iSCSI
38 | concepts, and finally provides guidance to system designers on how
39 | true command ordering solutions can be built based on iSCSI.
40 |
41 | Table of Contents
42 |
43 | 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2
44 | 2. Definitions and Acronyms . . . . . . . . . . . . . . . . . . . 3
45 | 2.1. Definitions. . . . . . . . . . . . . . . . . . . . . . . 3
46 | 2.2. Acronyms . . . . . . . . . . . . . . . . . . . . . . . . 4
47 | 3. Overview of the iSCSI Protocol . . . . . . . . . . . . . . . . 4
48 | 3.1. Protocol Mapping Description . . . . . . . . . . . . . . 4
49 | 3.2. The I_T Nexus Model. . . . . . . . . . . . . . . . . . . 5
50 | 3.3. Ordered Command Delivery . . . . . . . . . . . . . . . . 6
51 | 3.3.1. Questions. . . . . . . . . . . . . . . . . . . . 6
52 | 3.3.2. The Session Guarantee. . . . . . . . . . . . . . 6
53 | 3.3.3. Ordering Onus. . . . . . . . . . . . . . . . . . 7
54 | 3.3.4. Design Intent. . . . . . . . . . . . . . . . . . 7
55 |
56 |
57 |
58 | Chadalapaka & Elliott Informational [Page 1]
59 |
60 | RFC 3783 Command Ordering May 2004
61 |
62 |
63 | 4. The Command Ordering Scenario. . . . . . . . . . . . . . . . . 8
64 | 4.1. SCSI Layer . . . . . . . . . . . . . . . . . . . . . . . 8
65 | 4.1.1. Command Reference Number (CRN) . . . . . . . . . 8
66 | 4.1.2. Task Attributes. . . . . . . . . . . . . . . . . 8
67 | 4.1.3. Auto Contingent Allegiance (ACA) . . . . . . . . 8
68 | 4.1.4. UA Interlock . . . . . . . . . . . . . . . . . . 9
69 | 4.2. iSCSI Layer. . . . . . . . . . . . . . . . . . . . . . . 9
70 | 5. Connection Failure Considerations. . . . . . . . . . . . . . . 9
71 | 6. Command Ordering System Considerations . . . . . . . . . . . . 10
72 | 7. Reservation Considerations . . . . . . . . . . . . . . . . . . 11
73 | 8. Security Considerations. . . . . . . . . . . . . . . . . . . . 12
74 | 9. References and Bibliography. . . . . . . . . . . . . . . . . . 12
75 | 9.1. Normative References.. . . . . . . . . . . . . . . . . . 12
76 | 9.2. Informative References . . . . . . . . . . . . . . . . . 12
77 | 10. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 12
78 | 11. Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 13
79 | 12. Full Copyright Statement . . . . . . . . . . . . . . . . . . . 14
80 |
81 | 1. Introduction
82 |
83 | iSCSI is a SCSI transport protocol ([iSCSI]) designed to enable
84 | running SCSI application protocols on TCP/IP networks, including
85 | potentially the Internet. Given the size and scope of the Internet,
86 | iSCSI thus enables some exciting new SCSI applications. Potential
87 | new application areas for exploiting iSCSI's value include the
88 | following:
89 |
90 | a) Larger (diameter) Storage Area Networks (SANs) than had been
91 | possible until now
92 | b) Asynchronous remote mirroring
93 | c) Remote tape vaulting
94 |
95 | Each of these applications takes advantage of the practically
96 | unlimited geographical distance that iSCSI enables between a SCSI
97 | initiator and a SCSI target. In each of these cases, because of the
98 | long delays involved, there is a very high incentive for the
99 | initiator to stream SCSI commands back-to-back without waiting for
100 | the SCSI status of previous commands. Command streaming may be
101 | employed primarily by two classes of applications - while one class
102 | may not particularly care about ordered command execution, the other
103 | class does rely on ordered command execution (i.e. there is an
104 | application-level dependency on the ordering among SCSI commands).
105 | As an example, cases b) and c) listed earlier clearly require ordered
106 | command execution. A mirroring application does not want the writes
107 | to be committed out of order on the remote SCSI target, so as to
108 |
109 |
110 |
111 |
112 |
113 |
114 | Chadalapaka & Elliott Informational [Page 2]
115 |
116 | RFC 3783 Command Ordering May 2004
117 |
118 |
119 | preserve the transactional integrity of the data on that target. To
120 | summarize, SCSI command streaming, when coupled with the guarantee of
121 | ordered command execution on the SCSI target, is extremely valuable
122 | for a critical class of applications in long-latency networks.
123 |
124 | This document reviews the various protocol considerations in
125 | designing storage solutions that employ SCSI command ordering. This
126 | document also analyzes and explains the design intent of [iSCSI] with
127 | respect to command ordering.
128 |
129 | 2. Definitions and Acronyms
130 |
131 | 2.1. Definitions
132 |
133 | - I_T nexus: [SAM2] defines the I_T nexus as a relationship between
134 | a SCSI initiator port and a SCSI target port. [iSCSI] defines an
135 | iSCSI session as the iSCSI representation of an I_T nexus. In the
136 | iSCSI context, the I_T nexus (i.e. the iSCSI session) is a
137 | relationship between an iSCSI initiator's end of the session (SCSI
138 | Initiator Port) and the iSCSI target's Portal Group (SCSI Target
139 | Port).
140 |
141 | - PDU (Protocol Data Unit): An iSCSI initiator and iSCSI target
142 | communicate using iSCSI protocol messages. These messages are
143 | called "iSCSI protocol data units" (iSCSI PDUs).
144 |
145 | - SCSI device: A SCSI device is an entity that contains one or more
146 | SCSI ports that are connected to a service delivery subsystem and
147 | supports SCSI application protocols. In the iSCSI context, the
148 | SCSI Device is the component within an iSCSI Node that provides
149 | the SCSI functionality. The SCSI Device Name is defined to be the
150 | iSCSI Name of the node.
151 |
152 | - Session: A group of logically related iSCSI connections that link
153 | an initiator with a target form a session (equivalent to a SCSI
154 | I-T nexus). The number of participating iSCSI connections within
155 | an iSCSI session may vary over time. The multiplicity of
156 | connections at the iSCSI level is completely hidden for the SCSI
157 | layer - each SCSI port in an I_T nexus sees only one peer SCSI
158 | port across all the connections of a session.
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | Chadalapaka & Elliott Informational [Page 3]
171 |
172 | RFC 3783 Command Ordering May 2004
173 |
174 |
175 | 2.2. Acronyms
176 |
177 | Acronym Definition
178 | --------------------------------------------------------------
179 | ACA Auto Contingent Allegiance
180 | ASC Additional Sense Code
181 | ASCQ Additional Sense Code Qualifier
182 | CRN Command Reference Number
183 | IETF Internet Engineering Task Force
184 | ISID Initiator Session Identifier
185 | ITT Initiator Task Tag
186 | LU Logical Unit
187 | LUN Logical Unit Number
188 | NIC Network Interface Card
189 | PDU Protocol Data Unit
190 | TMF Task Management Function
191 | TSIH Target Session Identifying Handle
192 | SAN Storage Area Network
193 | SCSI Small Computer Systems Interface
194 | TCP Transmission Control Protocol
195 | UA Unit Attention
196 | WG Working Group
197 |
198 | 3. Overview of the iSCSI Protocol
199 |
200 | 3.1. Protocol Mapping Description
201 |
202 | The iSCSI protocol is a mapping of the SCSI remote procedure
203 | invocation model (see [SAM2]) over the TCP protocol.
204 |
205 | SCSI's notion of a task maps to an iSCSI task. Each iSCSI task is
206 | uniquely identified within that I_T nexus by a 32-bit unique
207 | identifier called Initiator Task Tag (ITT). The ITT is both an iSCSI
208 | identifier of the task and a classic SCSI task tag.
209 |
210 | SCSI commands from the initiator to the target are carried in iSCSI
211 | requests called SCSI Command PDUs. SCSI status back to the initiator
212 | is carried in iSCSI responses called SCSI Response PDUs. SCSI Data-
213 | out from the initiator to the target is carried in SCSI Data-Out
214 | PDUs, and the SCSI Data-in back to the initiator is carried in SCSI
215 | Data-in PDUs.
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 | Chadalapaka & Elliott Informational [Page 4]
227 |
228 | RFC 3783 Command Ordering May 2004
229 |
230 |
231 | 3.2. The I_T Nexus Model
232 |
233 | In the iSCSI model, the SCSI I_T nexus maps directly to the iSCSI
234 | session, which is an iSCSI protocol abstraction spanning one or more
235 | TCP connections. The iSCSI protocol defines the semantics in order
236 | to realize one logical flow of bidirectional communication on the I_T
237 | nexus, potentially spanning multiple TCP connections (as many as
238 | 2^16). The multiplicity of iSCSI connections is thus completely
239 | contained at the iSCSI layer, while the SCSI layer is presented with
240 | a single I_T nexus, even in a multi-connection session. A session
241 | between a pair of given iSCSI nodes is identified by the session
242 | identifier (SSID) and each connection within a given session is
243 | uniquely identified by a connection identifier (CID) in iSCSI. The
244 | SSID itself has two components - Initiator Session Identifier (ISID)
245 | and a Target Session Identifying Handler (TSIH) - each identifying
246 | one end of the same session.
247 |
248 | There are four crucial functional facets of iSCSI that together
249 | present this single logical flow abstraction to the SCSI layer, even
250 | with an iSCSI session spanning across multiple iSCSI connections.
251 |
252 | a) Ordered command delivery: A sequence of SCSI commands that is
253 | striped across all the connections in the session is
254 | "reordered" by the target iSCSI layer into an identical
255 | sequence based on a Command Sequence Number (CmdSN) that is
256 | unique across the session. The goal is to achieve bandwidth
257 | aggregation from multiple TCP connections, but to still make it
258 | appear to the target SCSI layer as if all the commands had
259 | travelled in one flow.
260 |
261 | b) Connection allegiance: All the PDU exchanges for a SCSI
262 | Command, up to and including the SCSI Response PDU for the
263 | Command, are required to flow on the same iSCSI connection at
264 | any given time. This again is intended to hide the multi-
265 | connection nature of a session because the SCSI layer on either
266 | side will never see the PDU contents out of order (e.g., status
267 | cannot bypass read data for an initiator).
268 |
269 | c) Task set management function handling: [iSCSI] specifies an
270 | ordered sequence of steps for the iSCSI layer on the SCSI
271 | target in handling the two SCSI task management functions
272 | (TMFs) that manage SCSI task sets. The two TMFs are ABORT TASK
273 | SET that aborts all active tasks in a session, and CLEAR TASK
274 | SET that clears the tasks in the task set. The goal of the
275 | sequence of steps is to guarantee that the initiator receives
276 | the SCSI Response PDUs of all unaffected tasks before the TMF
277 | Response itself arrives, regardless of the number of
278 | connections in the iSCSI session. This operational model is
279 |
280 |
281 |
282 | Chadalapaka & Elliott Informational [Page 5]
283 |
284 | RFC 3783 Command Ordering May 2004
285 |
286 |
287 | again intended to preserve the single flow abstraction to the
288 | SCSI layer.
289 |
290 | d) Immediate task management function handling: Even when a TMF
291 | request is marked as "immediate" (i.e. only has a position in
292 | the command stream, but does not consume a CmdSN), [iSCSI]
293 | defines semantics that require the target iSCSI layer to ensure
294 | that the TMF request is executed as if the commands and the TMF
295 | request were all flowing on a single logical channel. This
296 | ensures that the TMF request will act on tasks that it was
297 | meant to manage.
298 |
299 | The following sections will analyze the "Ordered command delivery"
300 | aspect in more detail, since command ordering is the focus of this
301 | document.
302 |
303 | 3.3. Ordered Command Delivery
304 |
305 | 3.3.1. Questions
306 |
307 | A couple of important questions related to iSCSI command ordering
308 | were considered early on in the design of the iSCSI protocol. The
309 | questions were:
310 |
311 | a) What should be the command ordering behavior required of iSCSI
312 | implementations in the presence of transport errors, such as
313 | errors that corrupt the data in a fashion that is not detected
314 | by the TCP checksum (e.g., two offsetting bit flips in the same
315 | bit position), but is detected by the iSCSI CRC digest?
316 |
317 | b) Should [iSCSI] require both initiators and targets to use
318 | ordered command delivery?
319 |
320 | Since the answers to these questions are critical to the
321 | understanding of the ordering behavior required by the iSCSI
322 | protocol, the following sub-sections consider them in more detail.
323 |
324 | 3.3.2. The Session Guarantee
325 |
326 | The final disposition of question a) in section 3.3.1 was reflected
327 | in [RFC3347], "iSCSI MUST specify strictly ordered delivery of SCSI
328 | commands over an iSCSI session between an initiator/target pair, even
329 | in the presence of transport errors." Stated differently, an iSCSI
330 | digest failure, or an iSCSI connection termination, must not cause
331 | the iSCSI layer on a target to allow executing the commands in an
332 | order different from that intended (as indicated by the CmdSN order)
333 | by the initiator. This design choice is enormously helpful in
334 | building storage systems and solutions that can now always assume
335 |
336 |
337 |
338 | Chadalapaka & Elliott Informational [Page 6]
339 |
340 | RFC 3783 Command Ordering May 2004
341 |
342 |
343 | command ordering to be a service characteristic of an iSCSI
344 | substrate.
345 |
346 | Note that by taking the position that an iSCSI session always
347 | guarantees command ordering, [iSCSI] was indirectly implying that the
348 | principal reason for the multi-connection iSCSI session abstraction
349 | was to allow ordered bandwidth aggregation for an I_T nexus. In
350 | deployment models where this cross-connection ordering mandated by
351 | [iSCSI] is deemed expensive, a serious consideration should be given
352 | to deploying multiple single-connection sessions instead.
353 |
354 | 3.3.3. Ordering Onus
355 |
356 | The final resolution of b) in section 3.3.1 by the iSCSI protocol
357 | designers was in favor of not always requiring the initiators to use
358 | command ordering. This resolution is reflected in dropping the
359 | mandatory ACA usage requirement on the initiators, and allowing an
360 | ABORT TASK TMF to plug a command hole etc., since these are conscious
361 | choices an initiator makes in favor of not using ordered command
362 | delivery. The net result can be discerned by a careful reader of
363 | [iSCSI] - the onus of ensuring ordered command delivery is always on
364 | the iSCSI targets, while the initiators may or may not utilize
365 | command ordering. iSCSI targets, being the servers in the client-
366 | server model, do not really attempt to establish whether or not a
367 | client (initiator) intends to take advantage of command ordering
368 | service, but instead simply always provide the guaranteed delivery
369 | service. The rationale here is that there are inherent SCSI and
370 | application-level dependencies, as we shall see in building a command
371 | ordered solution, that are beyond the scope of [iSCSI], to mandate or
372 | even discern the intent with respect to the usage of command
373 | ordering.
374 |
375 | 3.3.4. Design Intent
376 |
377 | To summarize the design intent of [iSCSI]:
378 |
379 | The service delivery subsystem (see [SAM2]) abstraction provided by
380 | an iSCSI session is guaranteed to have the intrinsic property of
381 | ordered delivery of commands to the target SCSI layer under all
382 | conditions. Consequently, the guarantee of the ordered command
383 | delivery is across the entire I_T nexus spanning all the LUs that the
384 | nexus is authorized to access. It is the initiator's discretion as
385 | to whether or not this property will be used.
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 | Chadalapaka & Elliott Informational [Page 7]
395 |
396 | RFC 3783 Command Ordering May 2004
397 |
398 |
399 | 4. The Command Ordering Scenario
400 |
401 | A storage systems designer working with SCSI and iSCSI has to
402 | consider the following protocol features in SCSI and iSCSI layers,
403 | each of which has a role to play in realizing the command ordering
404 | goal.
405 |
406 | 4.1. SCSI Layer
407 |
408 | The SCSI application layer has several tools to enforce ordering.
409 |
410 | 4.1.1. Command Reference Number (CRN)
411 |
412 | CRN is an ordered sequence number which, when enabled for a device
413 | server, increments by one for each I_T_L nexus (see [SAM2]). The one
414 | notable drawback with CRN is that there is no SCSI-generic way (such
415 | as through mode pages) to enable or disable the CRN feature. [SAM2]
416 | also leaves the usage semantics of CRN for the SCSI transport
417 | protocol, such as iSCSI, to specify. [iSCSI] chose not to support
418 | the CRN feature for various reasons.
419 |
420 | 4.1.2. Task Attributes
421 |
422 | [SAM2] defines the following four task attributes - SIMPLE, ORDERED,
423 | HEAD OF QUEUE, and ACA. Each task to an LU may be assigned an
424 | attribute. [SAM2] defines the ordering constraints that each of
425 | these attributes conveys to the device server that is servicing the
426 | task. In particular, judicious use of ORDERED and SIMPLE attributes
427 | applied to a stream of pipelined commands could convey the precise
428 | execution schema for the commands that the initiator issues, provided
429 | the commands are received in the same order on the target.
430 |
431 | 4.1.3. Auto Contingent Allegiance (ACA)
432 |
433 | ACA is an LU-level condition that is triggered when a command (with
434 | the NACA bit set to 1) completes with CHECK CONDITION. When ACA is
435 | triggered, it prevents all commands other than those with the ACA
436 | attribute from executing until the CLEAR ACA task management function
437 | is executed, while blocking all the other tasks already in the task
438 | set. See [SAM2] for the detailed semantics of ACA. Since ACA is
439 | closely tied to the notion of a task set, one would ideally have to
440 | select the scope of the task set (by setting the TST bit to 1 in the
441 | control mode page of the LU) to be per-initiator in order to prevent
442 | command failures in one I_T_L nexus from impacting other I_T_L
443 | nexuses through ACA.
444 |
445 |
446 |
447 |
448 |
449 |
450 | Chadalapaka & Elliott Informational [Page 8]
451 |
452 | RFC 3783 Command Ordering May 2004
453 |
454 |
455 | 4.1.4. UA Interlock
456 |
457 | When UA interlock is enabled, the logical unit does not clear any
458 | standard Unit Attention condition reported with autosense, and in
459 | addition, establishes a Unit Attention condition when a task is
460 | terminated with one of BUSY, TASK SET FULL, or RESERVATION CONFLICT
461 | statuses. This so-called "interlocked UA" is cleared only when the
462 | device server executes an explicit REQUEST SENSE ([SPC3]) command
463 | from the same initiator. From a functionality perspective, the scope
464 | of UA interlock today is slightly different from ACA's because it
465 | enforces ordering behavior for completion statuses other than CHECK
466 | CONDITION, but otherwise conceptually has the same design intent as
467 | ACA. On the other hand, ACA is somewhat more sophisticated because
468 | it allows special "cleanup" tasks (ones with ACA attribute) to
469 | execute when ACA is active. One of the principal reasons UA
470 | interlock came into being was that SCSI designers wanted a command
471 | ordering feature without the side effects of using the aforementioned
472 | TST bit in the control mode page.
473 |
474 | 4.2. iSCSI Layer
475 |
476 | As noted in section 3.2 and section 3.3, the iSCSI protocol enforces
477 | and guarantees ordered command delivery per iSCSI session using the
478 | CmdSN, and this is an attribute of the SCSI transport layer. Note
479 | further that any command ordering solution that seeks to realize
480 | ordering from the initiator SCSI layer to the target SCSI layer would
481 | be of practical value only when the command ordering is guaranteed by
482 | the SCSI transport layer. In other words, the related SCSI
483 | application layer protocol features such as ACA etc. are based on the
484 | premise of an ordered SCSI transport. Thus, iSCSI's command ordering
485 | is the last piece in completing the puzzle of building solutions that
486 | rely on ordered command execution, by providing the crucial guarantee
487 | that all the commands handed to the initiator iSCSI layer will be
488 | transported and handed to the target SCSI layer in the same order.
489 |
490 | 5. Connection Failure Considerations
491 |
492 | [iSCSI] mandates that when an iSCSI connection fails, the active
493 | tasks on that connection must be terminated if not recovered within a
494 | certain negotiated time limit. When an iSCSI target does terminate
495 | some subset of tasks due to iSCSI connection dynamics, there is a
496 | danger that the SCSI layer would simply move on to the next tasks
497 | waiting to be processed and execute them out-of-order unbeknownst to
498 | the initiator SCSI layer. To preclude this danger, [iSCSI] further
499 | mandates the following:
500 |
501 |
502 |
503 |
504 |
505 |
506 | Chadalapaka & Elliott Informational [Page 9]
507 |
508 | RFC 3783 Command Ordering May 2004
509 |
510 |
511 | a) The tasks terminated due to the connection failure must be
512 | internally terminated by the iSCSI target "as if" due to a
513 | CHECK CONDITION. While this particular completion status is
514 | never communicated back to the initiator, the "as if" is still
515 | meaningful and required because if the initiator were using ACA
516 | as the command ordering mechanism of choice, a SCSI-level ACA
517 | will be triggered due to this mandatory CHECK CONDITION. This
518 | addresses the aforementioned danger.
519 |
520 | b) After the tasks are terminated due to the connection failure,
521 | the iSCSI target must report a Unit Attention condition on the
522 | next command processed on any connection for each affected
523 | I_T_L nexus of that session. This is required because if the
524 | initiator were using UA interlock as the command ordering
525 | mechanism of choice, a SCSI-level UA will trigger a UA-
526 | interlock. This again addresses the aforementioned danger.
527 | iSCSI targets must report this UA with the status of CHECK
528 | CONDITION, and the ASC/ASCQ value of 47h/7Fh ("SOME COMMANDS
529 | CLEARED BY ISCSI PROTOCOL EVENT").
530 |
531 | 6. Command Ordering System Considerations
532 |
533 | In general, command ordering is automatically enforced if targets and
534 | initiators comply with the iSCSI specification. However, listed
535 | below are certain additional related implementation considerations
536 | for the iSCSI initiators and targets to take note of.
537 |
538 | a) Even when all iSCSI and SCSI command ordering considerations
539 | earlier noted in this document were applied, it is beneficial
540 | for iSCSI initiators to proactively avoid scenarios that would
541 | otherwise lead to out-of-order command execution. This is
542 | simply because the SCSI command ordering features such as UA
543 | interlock are likely to be costlier in performance when they
544 | are allowed to be triggered. [iSCSI] provides enough guidance
545 | on how to implement this proactive detection of PDU ordering
546 | errors.
547 |
548 | b) The whole notion of command streaming does of course assume
549 | that the target in question supports command queueing. An
550 | iSCSI target desirous of supporting command ordering solutions
551 | should ensure that the SCSI layer on the target supports
552 | command queuing. The remote backup (tape vaulting)
553 | applications that iSCSI enables make an especially compelling
554 | case that tape devices should give a very serious consideration
555 | to supporting command queuing, at least when used in
556 | conjunction with iSCSI.
557 |
558 |
559 |
560 |
561 |
562 | Chadalapaka & Elliott Informational [Page 10]
563 |
564 | RFC 3783 Command Ordering May 2004
565 |
566 |
567 | c) An iSCSI target desirous of supporting high-performance command
568 | ordering solutions that involve specifying a description of
569 | execution schema should ensure that the SCSI layer on the
570 | target in fact does support the ORDERED and SIMPLE task
571 | attributes.
572 |
573 | d) There is some consideration of expanding the scope of UA
574 | interlock to encompass CHECK CONDITION status, and thus make it
575 | the only required command ordering functionality of
576 | implementations to build command ordering solutions. Until
577 | this is resolved in T10, the currently defined semantics of UA
578 | interlock and ACA warrant implementing both features by iSCSI
579 | targets desirous of supporting command ordering solutions.
580 |
581 | 7. Reservation Considerations
582 |
583 | [iSCSI] describes a "principle of conservative reuse" that encourages
584 | iSCSI initiators to reuse the same ISIDs (see section 3.2) to various
585 | SCSI target ports, in order to present the same SCSI initiator port
586 | name to those target ports. This is in fact a very crucial
587 | implementation consideration that must be complied with. [SPC3]
588 | mandates the SCSI targets to associate persistent reservations and
589 | the related registrations with the SCSI initiator port names whenever
590 | they are required by the SCSI transport protocol. Since [iSCSI]
591 | requires the mandatory SCSI initiator port names based on ISIDs,
592 | iSCSI targets are required to work off the SCSI initiator port names,
593 | and thus indirectly the ISIDs, in enforcing the persistent
594 | reservations.
595 |
596 | This fact has the following implications for the implementations:
597 |
598 | a) If a persistent reservation/registration is intended to be used
599 | across multiple SCSI ports of a SCSI device, the initiator
600 | iSCSI implementation must use the same ISID across associated
601 | iSCSI sessions connecting to different iSCSI target portal
602 | groups of the SCSI device.
603 |
604 | b) If a persistent reservation/registration is intended to be used
605 | across the power loss of a SCSI target, the initiator iSCSI
606 | implementation must use the same ISIDs as before in
607 | re-establishing the associated iSCSI sessions upon subsequent
608 | reboot in order to rely on the persist through power loss
609 | capability.
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 | Chadalapaka & Elliott Informational [Page 11]
619 |
620 | RFC 3783 Command Ordering May 2004
621 |
622 |
623 | 8. Security Considerations
624 |
625 | For security considerations in using the iSCSI protocol, refer to the
626 | Security Considerations section in [iSCSI]. This document does not
627 | introduce any additional security considerations other than those
628 | already discussed in [iSCSI].
629 |
630 | 9. References
631 |
632 | 9.1. Normative References
633 |
634 | [iSCSI] Satran, J., Meth, K., Sapuntzakis, C., Chadalapaka, M. and
635 | E. Zeidner, "Internet Small Computer Systems Inferface
636 | (iSCSI)", RFC 3720, May 2004.
637 |
638 | [SAM2] ANSI INCITS.366:2003 SCSI Architecture Model - 2 (SAM-2).
639 |
640 | 9.2. Informative References
641 |
642 | [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC
643 | 793, September 1981.
644 |
645 | [RFC2119] Bradner, S., "Key Words for use in RFCs to Indicate
646 | Requirement Levels", BCP 14, RFC 2119, March 1997.
647 |
648 | [RFC3347] Krueger, M. and R. Haagens, "iSCSI Requirements and Design
649 | Considerations", RFC 3347, July 2002.
650 |
651 | [SPC3] INCITS T10/1416-D, SCSI Primary Commands-3 (SPC-3).
652 |
653 | 10. Acknowledgments
654 |
655 | We are grateful to the IPS working group whose work defined the iSCSI
656 | protocol. Thanks also to David Black (EMC) who encouraged the
657 | publication of this document. Special thanks to Randy Haagens (HP)
658 | for his insights on the topic of command ordering. Thanks are also
659 | due to Elizabeth Rodriguez for carefully reviewing this document.
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 | Chadalapaka & Elliott Informational [Page 12]
675 |
676 | RFC 3783 Command Ordering May 2004
677 |
678 |
679 | 11. Authors' Addresses
680 |
681 | Mallikarjun Chadalapaka
682 | Hewlett-Packard Company
683 | 8000 Foothills Blvd.
684 | Roseville, CA 95747-5668, USA
685 |
686 | Phone: +1.916.785.5621
687 | EMail: cbm@rose.hp.com
688 |
689 |
690 | Rob Elliott
691 | Hewlett-Packard Company
692 | MC140801
693 | PO Box 692000
694 | Houston, TX 77269-2000 USA
695 |
696 | Phone: +1.281.518.5037
697 | EMail: elliott@hp.com
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 | Chadalapaka & Elliott Informational [Page 13]
731 |
732 | RFC 3783 Command Ordering May 2004
733 |
734 |
735 | 12. Full Copyright Statement
736 |
737 | Copyright (C) The Internet Society (2004). This document is subject
738 | to the rights, licenses and restrictions contained in BCP 78, and
739 | except as set forth therein, the authors retain all their rights.
740 |
741 | This document and the information contained herein are provided on an
742 | "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
743 | OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
744 | ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
745 | INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
746 | INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
747 | WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
748 |
749 | Intellectual Property
750 |
751 | The IETF takes no position regarding the validity or scope of any
752 | Intellectual Property Rights or other rights that might be claimed to
753 | pertain to the implementation or use of the technology described in
754 | this document or the extent to which any license under such rights
755 | might or might not be available; nor does it represent that it has
756 | made any independent effort to identify any such rights. Information
757 | on the procedures with respect to rights in RFC documents can be
758 | found in BCP 78 and BCP 79.
759 |
760 | Copies of IPR disclosures made to the IETF Secretariat and any
761 | assurances of licenses to be made available, or the result of an
762 | attempt made to obtain a general license or permission for the use of
763 | such proprietary rights by implementers or users of this
764 | specification can be obtained from the IETF on-line IPR repository at
765 | http://www.ietf.org/ipr.
766 |
767 | The IETF invites any interested party to bring to its attention any
768 | copyrights, patents or patent applications, or other proprietary
769 | rights that may cover technology that may be required to implement
770 | this standard. Please address the information to the IETF at ietf-
771 | ipr@ietf.org.
772 |
773 | Acknowledgement
774 |
775 | Funding for the RFC Editor function is currently provided by the
776 | Internet Society.
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 | Chadalapaka & Elliott Informational [Page 14]
787 |
788 |
--------------------------------------------------------------------------------
/uSCSI/IoCtl.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | VOID SCSICompleteIrp (
5 | ULONG Handle , PVOID Ctx , UCHAR ScsiStatus , PUCHAR SenseData , ULONG SenseLen);
6 |
7 | NTSTATUS uFDOIoCtl (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
8 | {
9 | NTSTATUS Status = STATUS_SUCCESS;
10 | PIO_STACK_LOCATION Stack;
11 | PDEVICE_OBJECT DevPdo;
12 | PFDO_EXT FdoExt;
13 | PPDO_EXT PdoExt;
14 |
15 | Stack = IoGetCurrentIrpStackLocation( Irp );
16 | FdoExt = (PFDO_EXT)DeviceObject->DeviceExtension;
17 |
18 | switch ( Stack->Parameters.DeviceIoControl.IoControlCode )
19 | {
20 | case IOCTL_ISCSI_CREATE_SESSION:
21 | {
22 | ULONG Len;
23 | PUCHAR Target;
24 | PVOID Session;
25 | USCSI_CALL_BACK C = {0};
26 |
27 | Target = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
28 |
29 | if ( Target[Stack->Parameters.DeviceIoControl.InputBufferLength-1] != '\0' ||
30 | ( Len = strlen ( Target ) ) != Stack->Parameters.DeviceIoControl.InputBufferLength -1 )
31 | {
32 | Status = STATUS_INVALID_PARAMETER;
33 | }
34 | else
35 | {
36 | Status = IoCreateDevice(DeviceObject->DriverObject,
37 | sizeof(PDO_EXT) , //user size
38 | NULL, //Name
39 | FILE_DEVICE_UNKNOWN, //Device Type
40 | FILE_DEVICE_SECURE_OPEN|
41 | FILE_AUTOGENERATED_DEVICE_NAME, //Characteristics
42 | TRUE, //Exclusive
43 | &DevPdo);
44 |
45 | if ( NT_SUCCESS(Status) )
46 | {
47 | PdoExt = (PPDO_EXT)DevPdo->DeviceExtension;
48 |
49 | InitializeListHead ( &PdoExt->PDOList);
50 | PdoExt->IsFDO = FALSE;
51 | PdoExt->Reported = FALSE;
52 | PdoExt->Self = DevPdo;
53 |
54 | PdoExt->Target =
55 | ExAllocatePoolWithTag ( PagedPool , Len + 1 , USCSI_TAG );
56 | RtlCopyMemory ( PdoExt->Target , Target , Len + 1 );
57 |
58 | C.CompleteCmd = SCSICompleteIrp;
59 | C.CompleteCtx = PdoExt;
60 | PdoExt->Session = uSCSICreateSession ( PdoExt->Target , &C);
61 |
62 | if ( PdoExt->Session )
63 | {
64 | ExInterlockedInsertTailList ( &FdoExt->PDOList ,
65 | &PdoExt->PDOList,
66 | &FdoExt->PDOLock);
67 | FdoExt->PDOCount++;
68 | IoInvalidateDeviceRelations ( FdoExt->LowerDev , BusRelations );
69 | //DbgPrint("%s Session to Target %s Created\n" , __FUNCTION__, PdoExt->Target );
70 | }
71 | else
72 | {
73 | if ( DevPdo )
74 | IoDeleteDevice ( DevPdo );
75 | Status = STATUS_UNSUCCESSFUL;
76 | }
77 | }
78 | }
79 | }
80 | break;
81 |
82 | case IOCTL_ISCSI_ADD_TARGETS:
83 | {
84 | PTGTS Tgts;
85 | PTGT Tgt;
86 | ULONG i;
87 | Tgts = (PTGTS)Irp->AssociatedIrp.SystemBuffer;
88 |
89 | if ( sizeof (TGTS) > Stack->Parameters.DeviceIoControl.InputBufferLength)
90 | Status = STATUS_BUFFER_TOO_SMALL;
91 |
92 | else if ( Tgts->Size != Stack->Parameters.DeviceIoControl.InputBufferLength )
93 | Status = STATUS_INVALID_PARAMETER;
94 |
95 | else
96 | {
97 | Tgt = (PTGT)(Tgts + 1);
98 | for ( i = 0 ; i < Tgts->Count ; i++ )
99 | {
100 | uSCSIAddTarget ( Tgt->TargetName , Tgt->Addr , Tgt->Port );
101 | Tgt++;
102 | }
103 | }
104 | }
105 | break;
106 |
107 | case IOCTL_ISCSI_GET_TARGETS:
108 | {
109 | PTGTS Tgts;
110 | PTGT Tgt;
111 | Tgts = (PTGTS)Irp->AssociatedIrp.SystemBuffer;
112 |
113 | if ( sizeof (TGTS) > Stack->Parameters.DeviceIoControl.InputBufferLength)
114 | Status = STATUS_BUFFER_TOO_SMALL;
115 |
116 | else if ( !Tgts->Size )
117 | {
118 | Tgts->Size = uSCSIGetTargetsSize();
119 | Irp->IoStatus.Information = Stack->Parameters.DeviceIoControl.OutputBufferLength;
120 | }
121 |
122 | else if ( Tgts->Size != Stack->Parameters.DeviceIoControl.InputBufferLength )
123 | Status = STATUS_INVALID_PARAMETER;
124 |
125 | else
126 | {
127 | Status = uSCSIPopTargets ( Tgts );
128 | Irp->IoStatus.Information = Stack->Parameters.DeviceIoControl.OutputBufferLength;
129 | }
130 | }
131 | break;
132 | }
133 |
134 | Irp->IoStatus.Status = Status;
135 | IoCompleteRequest ( Irp , IO_NO_INCREMENT );
136 | return Status;
137 | }
138 |
139 | //
140 | //
141 | //
142 |
143 | NTSTATUS uPDOIoCtl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
144 | {
145 | NTSTATUS Status = STATUS_SUCCESS;
146 | PIO_STACK_LOCATION Stack;
147 | PPDO_EXT Ext;
148 |
149 | Stack = IoGetCurrentIrpStackLocation( Irp );
150 | Ext = (PPDO_EXT)DeviceObject->DeviceExtension;
151 |
152 | switch (Stack->Parameters.DeviceIoControl.IoControlCode)
153 | {
154 | case IOCTL_STORAGE_QUERY_PROPERTY:
155 | {
156 | PSTORAGE_PROPERTY_QUERY PropQuery;
157 | PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader;
158 | PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor;
159 | PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor;
160 |
161 | PropQuery = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
162 |
163 | if (sizeof (STORAGE_PROPERTY_QUERY) >
164 | Stack->Parameters.DeviceIoControl.InputBufferLength)
165 | {
166 | Status = STATUS_INVALID_PARAMETER;
167 | Irp->IoStatus.Information = 0;
168 | }
169 | else
170 | {
171 | /*
172 | PropertyId:
173 | StorageDeviceProperty = 0,
174 | StorageAdapterProperty,
175 | StorageDeviceIdProperty,
176 | StorageDeviceUniqueIdProperty, // See storduid.h for details
177 | StorageDeviceWriteCacheProperty,
178 | StorageMiniportProperty,
179 | StorageAccessAlignmentProperty,
180 | StorageDeviceSeekPenaltyProperty,
181 | StorageDeviceTrimProperty,
182 | StorageDeviceWriteAggregationProperty
183 | */
184 | /*
185 | QueryType:
186 | PropertyStandardQuery = 0,
187 | PropertyExistsQuery,
188 | PropertyMaskQuery,
189 | PropertyQueryMaxDefined
190 | */
191 | DbgPrint("%s IOCTL_STORAGE_QUERY_PROPERTY PropertyId=0x%X QueryType=0x%X\n" ,
192 | __FUNCTION__ , PropQuery->PropertyId , PropQuery->QueryType);
193 |
194 | if (StorageDeviceProperty == PropQuery->PropertyId)
195 | {
196 |
197 | if ( sizeof (STORAGE_DESCRIPTOR_HEADER) ==
198 | Stack->Parameters.DeviceIoControl.OutputBufferLength)
199 | {
200 | DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer;
201 | DescriptorHeader->Version = 1;
202 | DescriptorHeader->Size =
203 | sizeof (STORAGE_DEVICE_DESCRIPTOR)+22;
204 | Irp->IoStatus.Information = sizeof (STORAGE_DESCRIPTOR_HEADER);
205 | }
206 | else
207 | {
208 | DeviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
209 |
210 | DeviceDescriptor->Version = 1;
211 | DeviceDescriptor->Size = sizeof (STORAGE_DEVICE_DESCRIPTOR);
212 | DeviceDescriptor->DeviceType = DIRECT_ACCESS_DEVICE;
213 | DeviceDescriptor->DeviceTypeModifier = 0;
214 | DeviceDescriptor->RemovableMedia = FALSE;
215 | DeviceDescriptor->CommandQueueing = FALSE;
216 | DeviceDescriptor->VendorIdOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR);
217 | DeviceDescriptor->ProductIdOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR)+8;
218 | DeviceDescriptor->ProductRevisionOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR)+14;
219 | DeviceDescriptor->SerialNumberOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR)+17;
220 | DeviceDescriptor->BusType = BusTypeiScsi;
221 | DeviceDescriptor->RawPropertiesLength = 22;
222 | RtlCopyMemory(&DeviceDescriptor->RawDeviceProperties[DeviceDescriptor->VendorIdOffset],"yushang\0",8);
223 | RtlCopyMemory(&DeviceDescriptor->RawDeviceProperties[DeviceDescriptor->ProductIdOffset],"uSCSI\0",6);
224 | RtlCopyMemory(&DeviceDescriptor->RawDeviceProperties[DeviceDescriptor->ProductRevisionOffset],"r1\0",3);
225 | RtlCopyMemory(&DeviceDescriptor->RawDeviceProperties[DeviceDescriptor->SerialNumberOffset],"A123\0",5);
226 | //
227 | Irp->IoStatus.Information = sizeof (STORAGE_DEVICE_DESCRIPTOR);
228 | }
229 | }
230 | else if ( StorageAdapterProperty == PropQuery->PropertyId )
231 | {
232 | if ( sizeof (STORAGE_DESCRIPTOR_HEADER) ==
233 | Stack->Parameters.DeviceIoControl.OutputBufferLength)
234 | {
235 | DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer;
236 | DescriptorHeader->Version = 1;
237 | DescriptorHeader->Size = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
238 | Irp->IoStatus.Information = sizeof (STORAGE_DESCRIPTOR_HEADER);
239 | }
240 | else
241 | {
242 | AdapterDescriptor = (PSTORAGE_ADAPTER_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
243 |
244 | AdapterDescriptor->Version = 20;
245 | AdapterDescriptor->Size = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
246 | AdapterDescriptor->MaximumTransferLength = 0x40*0x1000;//0x40000;
247 | AdapterDescriptor->MaximumPhysicalPages = 0x41;
248 | AdapterDescriptor->AlignmentMask = 0x3;
249 | AdapterDescriptor->AdapterUsesPio = FALSE;
250 | AdapterDescriptor->AdapterScansDown = FALSE;
251 | AdapterDescriptor->CommandQueueing = FALSE;
252 | AdapterDescriptor->AcceleratedTransfer = FALSE;
253 | AdapterDescriptor->BusType = BusTypeiScsi;
254 | AdapterDescriptor->BusMajorVersion = 2;
255 | AdapterDescriptor->BusMinorVersion = 0;
256 | Irp->IoStatus.Information = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
257 | }
258 | }
259 | else
260 | {
261 | DbgPrint("*** IOCTL_STORAGE_QUERY_PROPERTY Unprocessed PropertyId=0x%X\n" , PropQuery->PropertyId);
262 | }
263 | }
264 | }
265 | break;
266 |
267 | case IOCTL_DISK_GET_DRIVE_GEOMETRY:
268 | {
269 | PDISK_GEOMETRY Geo = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer;
270 |
271 | DbgPrint("%s IOCTL_DISK_GET_DRIVE_GEOMETRY\n" , __FUNCTION__ );
272 |
273 | if (sizeof (DISK_GEOMETRY) > Stack->Parameters.DeviceIoControl.OutputBufferLength)
274 | {
275 | Status = STATUS_INVALID_PARAMETER;
276 | Irp->IoStatus.Information = 0;
277 | }
278 | else
279 | {
280 | // 256M
281 | Geo->Cylinders.LowPart = 0x100;
282 | Geo->Cylinders.HighPart = 0;
283 | Geo->MediaType = FixedMedia;
284 | Geo->TracksPerCylinder = 0x100;
285 | Geo->SectorsPerTrack = 0x4;
286 | Geo->BytesPerSector = 0x400;
287 | Irp->IoStatus.Information = sizeof (DISK_GEOMETRY);
288 | }
289 | }
290 | break;
291 |
292 | case IOCTL_SCSI_GET_ADDRESS:
293 | {
294 | PSCSI_ADDRESS Addr;
295 | Addr = (PSCSI_ADDRESS)Irp->AssociatedIrp.SystemBuffer;
296 |
297 | DbgPrint("%s IOCTL_SCSI_GET_ADDRESS\n" , __FUNCTION__ );
298 |
299 | if ( sizeof (SCSI_ADDRESS) > Stack->Parameters.DeviceIoControl.OutputBufferLength )
300 | {
301 | Status = STATUS_INVALID_PARAMETER;
302 | Irp->IoStatus.Information = 0;
303 | }
304 | else
305 | {
306 | Addr->Length = sizeof (SCSI_ADDRESS);
307 | Addr->PortNumber = 1;
308 | Addr->PathId = 1;
309 | Addr->TargetId = 1;
310 | Addr->Lun = 0;
311 | Irp->IoStatus.Information = sizeof (SCSI_ADDRESS);
312 | }
313 | }
314 | break;
315 |
316 | case IOCTL_SCSI_PASS_THROUGH_DIRECT:
317 | DbgPrint("%s IOCTL_SCSI_PASS_THROUGH_DIRECT\n" , __FUNCTION__ );
318 | break;
319 |
320 | case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
321 | DbgPrint("%s IOCTL_MOUNTDEV_QUERY_STABLE_GUID\n" , __FUNCTION__ );
322 | break;
323 |
324 | case IOCTL_MOUNTDEV_LINK_CREATED:
325 | DbgPrint("%s IOCTL_MOUNTDEV_LINK_CREATED\n" , __FUNCTION__ );
326 | break;
327 |
328 | case IOCTL_VOLUME_ONLINE:
329 | DbgPrint("%s IOCTL_VOLUME_ONLINE\n" , __FUNCTION__ );
330 | break;
331 |
332 | case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
333 | DbgPrint("%s IOCTL_VOLUME_GET_GPT_ATTRIBUTES\n" , __FUNCTION__ );
334 | break;
335 |
336 | case IOCTL_SCSI_MINIPORT:
337 | {
338 | PSRB_IO_CONTROL IoCtl;
339 | IoCtl = (PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer;
340 |
341 | DbgPrint("IOCTL_SCSI_MINIPORT HeaderLength=0x%X Signature=%c%c%c%c%c%c%c%c Timeout=0x%X ControlCode=0x%X ReturnCode=0x%X Length=0x%X\n",
342 | IoCtl->HeaderLength,
343 | IoCtl->Signature[0],IoCtl->Signature[1],IoCtl->Signature[2],IoCtl->Signature[3],
344 | IoCtl->Signature[4],IoCtl->Signature[5],IoCtl->Signature[6],IoCtl->Signature[7],
345 | IoCtl->Timeout ,
346 | IoCtl->ControlCode,
347 | IoCtl->ReturnCode,
348 | IoCtl->Length);
349 | }
350 | break;
351 | //HD Tune Pro 5.0
352 | /*
353 | case IOCTL_ATA_PASS_THROUGH:
354 | {
355 | PATA_PASS_THROUGH_EX Pat;
356 | DbgPrint("%s IOCTL_ATA_PASS_THROUGH\n" , __FUNCTION__ );
357 |
358 | if ( sizeof(ATA_PASS_THROUGH_EX) >
359 | Stack->Parameters.DeviceIoControl.InputBufferLength )
360 | {
361 | Status = STATUS_INVALID_PARAMETER;
362 | }
363 | else
364 | {
365 | Pat = (PATA_PASS_THROUGH_EX)Irp->AssociatedIrp.SystemBuffer;
366 | DbgPrint("PathId.TargetId.Lun=0x%X.%X.%X AtaFlags=0x%X DataTransferLength=0x%X\n" ,
367 | Pat->PathId,Pat->TargetId,Pat->Lun,
368 | Pat->AtaFlags,Pat->DataTransferLength);
369 | if ( Pat->AtaFlags & ATA_FLAGS_DATA_IN &&
370 | (Pat->DataTransferLength + sizeof(ATA_PASS_THROUGH_EX)) >
371 | Stack->Parameters.DeviceIoControl.InputBufferLength )
372 | Status = STATUS_INVALID_PARAMETER;
373 | else
374 | {
375 |
376 | }
377 | }
378 |
379 | }
380 | break;
381 | */
382 | //ntddft.h
383 | case FT_BALANCED_READ_MODE:
384 | Status = STATUS_UNSUCCESSFUL;
385 | DbgPrint("%s FT_BALANCED_READ_MODE\n" , __FUNCTION__ );
386 | break;
387 |
388 | default:
389 | DbgPrint("%s *** Unprocessed IoControlCode 0x%X (DevType 0x%X , Function 0x%X)\n" ,
390 | __FUNCTION__ ,
391 | Stack->Parameters.DeviceIoControl.IoControlCode,
392 | DEVICE_TYPE_FROM_CTL_CODE(Stack->Parameters.DeviceIoControl.IoControlCode),
393 | FUNC_CODE(Stack->Parameters.DeviceIoControl.IoControlCode));
394 |
395 | break;
396 | }
397 |
398 | Irp->IoStatus.Status = Status;
399 | IoCompleteRequest ( Irp , IO_NO_INCREMENT );
400 | return Status;
401 | }
402 |
403 | //
404 | // IRP_MJ_DEVICE_CONTROL
405 | //
406 |
407 | NTSTATUS uIoCtl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
408 | {
409 | PCOMMON_EXT Ext;
410 | Ext = (PCOMMON_EXT)DeviceObject->DeviceExtension;
411 |
412 | if ( Ext->IsFDO )
413 | return uFDOIoCtl ( DeviceObject , Irp );
414 | else
415 | return uPDOIoCtl ( DeviceObject , Irp );
416 | }
417 |
418 |
--------------------------------------------------------------------------------
/uSCSI/MAKEFILE:
--------------------------------------------------------------------------------
1 | #
2 | # DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
3 | # file to this component. This file merely indirects to the real make file
4 | # that is shared by all the driver components of the Windows NT DDK
5 | #
6 |
7 | !INCLUDE $(NTMAKEENV)\makefile.def
8 |
9 |
--------------------------------------------------------------------------------
/uSCSI/Pnp.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | NTSTATUS uStartFdo(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
5 | {
6 | NTSTATUS Status = STATUS_SUCCESS;
7 | PIO_STACK_LOCATION Stack;
8 | PFDO_EXT FdoExt;
9 | PDEVICE_RELATIONS Rels;
10 |
11 | Stack = IoGetCurrentIrpStackLocation( Irp );
12 | FdoExt = DeviceObject->DeviceExtension;
13 |
14 | Status = SendIrpSynchronously(FdoExt->LowerDev,Irp);
15 | if (NT_ERROR(Status))
16 | goto ErrorOut;
17 |
18 | Status = IoSetDeviceInterfaceState (&FdoExt->InterfaceName , TRUE );
19 | if (NT_ERROR(Status))
20 | goto ErrorOut;
21 |
22 | uSCSIInitialize();
23 |
24 | return Status;
25 |
26 | ErrorOut:
27 |
28 | return Status;
29 | }
30 |
31 | NTSTATUS uPnPFdo (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
32 | {
33 | NTSTATUS Status = STATUS_SUCCESS;
34 | ULONG i = 0 , OldCount;
35 | PIO_STACK_LOCATION Stack;
36 | PLIST_ENTRY PdoEnt , PdoEnt2;
37 | PFDO_EXT FdoExt;
38 | PPDO_EXT PdoExt;
39 | PDEVICE_RELATIONS OldRels , Rels;
40 |
41 | Stack = IoGetCurrentIrpStackLocation( Irp );
42 | FdoExt = DeviceObject->DeviceExtension;
43 |
44 | KdPrintEx((DPFLTR_USCSI,DBG_USCSI,
45 | "%s MinorFunction 0x%X\n" , __FUNCTION__ , Stack->MinorFunction));
46 |
47 | switch (Stack->MinorFunction )
48 | {
49 | case IRP_MN_START_DEVICE:
50 |
51 | Status = uStartFdo (DeviceObject , Irp);
52 |
53 | break;
54 |
55 | case IRP_MN_QUERY_DEVICE_RELATIONS:
56 |
57 | if ( BusRelations == Stack->Parameters.QueryDeviceRelations.Type )
58 | {
59 | OldRels = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
60 | if (OldRels)
61 | OldCount = OldRels->Count;
62 | else
63 | OldCount = 0;
64 |
65 | Rels = ExAllocatePoolWithTag(PagedPool ,
66 | sizeof (DEVICE_RELATIONS) +
67 | (FdoExt->PDOCount + OldCount - 1)*sizeof (PDEVICE_OBJECT),
68 | USCSI_TAG );
69 |
70 | if ( Rels )
71 | {
72 | if (OldCount)
73 | RtlCopyMemory (Rels->Objects, OldRels->Objects,
74 | OldCount * sizeof (PDEVICE_OBJECT));
75 |
76 | Rels->Count = OldCount + FdoExt->PDOCount;
77 |
78 | PdoEnt = &FdoExt->PDOList;
79 | PdoEnt2 = PdoEnt->Flink;
80 |
81 | while ( PdoEnt2 != PdoEnt )
82 | {
83 | PdoExt = CONTAINING_RECORD ( PdoEnt2, PDO_EXT , PDOList);
84 | if ( !PdoExt->Reported )
85 | {
86 | ObReferenceObject( PdoExt->Self );
87 | Rels->Objects[OldCount++] = PdoExt->Self;
88 | PdoExt->Reported = TRUE;
89 | }
90 | PdoEnt2 = PdoEnt2->Flink;
91 | }
92 |
93 | Irp->IoStatus.Information = (ULONG_PTR)Rels;
94 | }
95 | }
96 | break;
97 |
98 | case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
99 | case IRP_MN_QUERY_CAPABILITIES:
100 | case IRP_MN_QUERY_PNP_DEVICE_STATE:
101 |
102 | IoSkipCurrentIrpStackLocation( Irp );
103 |
104 | Status = IoCallDriver ( FdoExt->LowerDev , Irp );
105 |
106 | return Status;
107 |
108 | case 0x18:
109 | //IRP_MN_QUERY_LEGACY_BUS_INFORMATION
110 | Status = SendIrpSynchronously( FdoExt->LowerDev , Irp );
111 | break;
112 | }
113 |
114 | Irp->IoStatus.Status = Status;
115 |
116 | IoCompleteRequest( Irp , IO_NO_INCREMENT );
117 |
118 | return Status;
119 | }
120 |
121 | NTSTATUS uStartPdo (IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
122 | {
123 | NTSTATUS Status = STATUS_SUCCESS;
124 | PPDO_EXT PdoExt;
125 |
126 | PdoExt = (PPDO_EXT)DeviceObject->DeviceExtension;
127 |
128 | InitializeListHead ( &PdoExt->PDOList);
129 | InitializeListHead ( &PdoExt->CmdQueue);
130 | KeInitializeSpinLock ( &PdoExt->CmdQueueLock);
131 | /*
132 | ExInitializePagedLookasideList (
133 | &PdoExt->CmdLookAside , NULL , NULL , 0 , sizeof (SCSICmd) , USCSI_TAG , 0);*/
134 |
135 | return Status;
136 |
137 | }
138 |
139 | //
140 | //
141 | //
142 |
143 | NTSTATUS uPnPPdo (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
144 | {
145 | NTSTATUS Status = STATUS_SUCCESS;
146 | PIO_STACK_LOCATION Stack;
147 | PPDO_EXT PdoExt;
148 | PWCHAR Id = NULL;
149 |
150 | Stack = IoGetCurrentIrpStackLocation( Irp );
151 | PdoExt = DeviceObject->DeviceExtension;
152 |
153 | KdPrintEx((DPFLTR_USCSI,DBG_USCSI,
154 | "%s MinorFunction 0x%X\n" , __FUNCTION__ , Stack->MinorFunction ));
155 |
156 | switch (Stack->MinorFunction)
157 | {
158 | case IRP_MN_START_DEVICE:
159 |
160 | uStartPdo ( DeviceObject , Irp );
161 | break;
162 |
163 | case IRP_MN_QUERY_ID:
164 |
165 | if (BusQueryHardwareIDs == Stack->Parameters.QueryId.IdType ||
166 | BusQueryCompatibleIDs == Stack->Parameters.QueryId.IdType )
167 | {
168 | Id = ExAllocatePoolWithTag (PagedPool , HARDWAREID_LEN , USCSI_TAG);
169 | if ( Id )
170 | {
171 | RtlCopyMemory ( Id , HARDWAREID , HARDWAREID_LEN );
172 | Irp->IoStatus.Information = (ULONG_PTR)Id;
173 | }
174 | else
175 | Status = STATUS_UNSUCCESSFUL;
176 |
177 | }
178 | else if ( BusQueryDeviceID == Stack->Parameters.QueryId.IdType )
179 | {
180 | Id = ExAllocatePoolWithTag (PagedPool ,DEVICEID_LEN ,USCSI_TAG);
181 | if ( Id )
182 | {
183 | RtlCopyMemory ( Id , DEVICEID , DEVICEID_LEN );
184 | Irp->IoStatus.Information = (ULONG_PTR)Id;
185 | }
186 | else
187 | Status = STATUS_UNSUCCESSFUL;
188 | }
189 | /*
190 | else if ( BusQueryInstanceID == Stack->Parameters.QueryId.IdType )
191 | {
192 | Id = ExAllocatePoolWithTag ( PagedPool , 2 , USCSI_TAG);
193 | if ( Id )
194 | {
195 | RtlCopyMemory ( Id , L"\0" , 2 );
196 | Irp->IoStatus.Information = (ULONG_PTR)Id;
197 | }
198 | else
199 | Status = STATUS_UNSUCCESSFUL;
200 | }*/
201 | KdPrintEx((DPFLTR_USCSI,DBG_USCSI,
202 | "%s IdType %d Id %ws\n" , __FUNCTION__ ,
203 | Stack->Parameters.QueryId.IdType , Id ));
204 | break;
205 |
206 | case IRP_MN_QUERY_DEVICE_TEXT:
207 |
208 | // Description
209 | if (DeviceTextDescription ==
210 | Stack->Parameters.QueryDeviceText.DeviceTextType)
211 | {
212 | Id = ExAllocatePoolWithTag ( PagedPool , DEVICEDESC_LEN , USCSI_TAG);
213 | if (Id)
214 | {
215 | RtlCopyMemory ( Id , DEVICEDESC , DEVICEDESC_LEN );
216 | Irp->IoStatus.Information = (ULONG_PTR)Id;
217 | }
218 | else
219 | Status = STATUS_UNSUCCESSFUL;
220 | }
221 | // Location info
222 | else if (DeviceTextLocationInformation ==
223 | Stack->Parameters.QueryDeviceText.DeviceTextType)
224 | {
225 | Id = ExAllocatePoolWithTag ( PagedPool , DEVICELOC_LEN , USCSI_TAG);
226 | if (Id)
227 | {
228 | RtlCopyMemory ( Id , DEVICELOC , DEVICELOC_LEN );
229 | Irp->IoStatus.Information = (ULONG_PTR)Id;
230 | }
231 | else
232 | Status = STATUS_UNSUCCESSFUL;
233 | }
234 | KdPrintEx((DPFLTR_USCSI,DBG_USCSI,
235 | "%s Text %d Id %ws\n" , __FUNCTION__ ,
236 | Stack->Parameters.QueryDeviceText.DeviceTextType , Id ));
237 | break;
238 |
239 | case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
240 |
241 | Status = Irp->IoStatus.Status;
242 |
243 | IoCompleteRequest( Irp , IO_NO_INCREMENT );
244 |
245 | return Status;
246 |
247 | case IRP_MN_QUERY_RESOURCES:
248 | {
249 | PCM_RESOURCE_LIST Res;
250 | Res = ExAllocatePoolWithTag ( PagedPool , sizeof (CM_RESOURCE_LIST) ,
251 | USCSI_TAG);
252 | if ( Res )
253 | {
254 | Res->Count = 1;
255 | Res->List[0].PartialResourceList.Version = 1;
256 | Res->List[0].PartialResourceList.Revision = 1;
257 | Res->List[0].PartialResourceList.Count = 0;
258 | Irp->IoStatus.Information = (ULONG_PTR)Res;
259 | }
260 | else
261 | {
262 | Irp->IoStatus.Information = 0;
263 | Status = STATUS_INSUFFICIENT_RESOURCES;
264 | }
265 | }
266 | break;
267 |
268 | case IRP_MN_QUERY_BUS_INFORMATION:
269 | {
270 | PPNP_BUS_INFORMATION businfo;
271 | businfo = ExAllocatePoolWithTag (PagedPool, sizeof(PNP_BUS_INFORMATION),
272 | USCSI_TAG);
273 | //businfo->BusTypeGuid = GUID_USCSI_BUS;
274 | businfo->LegacyBusType = PNPBus;
275 | businfo->BusNumber = 0;
276 | }
277 | break;
278 |
279 | case IRP_MN_QUERY_CAPABILITIES:
280 | {
281 | PDEVICE_CAPABILITIES Caps;
282 | Caps = Stack->Parameters.DeviceCapabilities.Capabilities;
283 |
284 | Caps->LockSupported = FALSE;
285 | Caps->EjectSupported = FALSE;
286 | Caps->Removable = FALSE;
287 | Caps->DockDevice = FALSE;
288 | Caps->D1Latency = Caps->D2Latency = Caps->D3Latency = 0;
289 | Caps->NoDisplayInUI = 1;
290 | Irp->IoStatus.Information = sizeof (DEVICE_CAPABILITIES);
291 | }
292 | break;
293 |
294 | case IRP_MN_QUERY_PNP_DEVICE_STATE:
295 | {
296 | Irp->IoStatus.Information = 0;
297 | }
298 | break;
299 | }
300 |
301 | Irp->IoStatus.Status = Status;
302 |
303 | IoCompleteRequest( Irp , IO_NO_INCREMENT );
304 |
305 | return Status;
306 | }
307 |
308 | //
309 | //
310 | //
311 |
312 | NTSTATUS uPnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
313 | {
314 | PCOMMON_EXT Ext;
315 |
316 | Ext = (PCOMMON_EXT)DeviceObject->DeviceExtension;
317 |
318 | if ( Ext->IsFDO )
319 | return uPnPFdo (DeviceObject , Irp );
320 | else
321 | return uPnPPdo (DeviceObject , Irp );
322 | }
--------------------------------------------------------------------------------
/uSCSI/Public.h:
--------------------------------------------------------------------------------
1 | #ifndef _USCSI_PUBLIC_H
2 | #define _USCSI_PUBLIC_H
3 |
4 | #include
5 |
6 | #include
7 |
8 | // {A10A82EB-E4FC-4d1d-9F5A-DFA326E393F5}
9 | static const GUID USCSI_DISK_INTERFACE =
10 | { 0xa10a82eb, 0xe4fc, 0x4d1d, { 0x9f, 0x5a, 0xdf, 0xa3, 0x26, 0xe3, 0x93, 0xf5 } };
11 |
12 | #define FILE_DEVICE_USCSI 43
13 |
14 | #define BUSENUM_IOCTL(_index_) \
15 | CTL_CODE (FILE_DEVICE_USCSI, _index_, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
16 |
17 | #define IOCTL_ISCSI_CREATE_SESSION BUSENUM_IOCTL (0x01)
18 | #define IOCTL_ISCSI_ADD_TARGETS BUSENUM_IOCTL (0x02)
19 | #define IOCTL_ISCSI_GET_TARGETS BUSENUM_IOCTL (0x03)
20 |
21 | #endif
--------------------------------------------------------------------------------
/uSCSI/ReadWrite.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | //
5 | //
6 | //
7 |
8 | NTSTATUS uFlush (IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
9 | {
10 | NTSTATUS Status = STATUS_SUCCESS;
11 | PIO_STACK_LOCATION Stack;
12 |
13 | Stack = IoGetCurrentIrpStackLocation( Irp );
14 |
15 | Irp->IoStatus.Status = Status;
16 | IoCompleteRequest( Irp , IO_NO_INCREMENT );
17 | return Status;
18 | }
19 |
20 | //
21 | //
22 | //
23 |
24 | NTSTATUS uCreateClose (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
25 | {
26 | NTSTATUS Status = STATUS_SUCCESS;
27 | PIO_STACK_LOCATION Stack;
28 |
29 | Stack = IoGetCurrentIrpStackLocation( Irp );
30 |
31 | Irp->IoStatus.Status = Status;
32 | IoCompleteRequest( Irp , IO_NO_INCREMENT );
33 | return Status;
34 | }
35 |
36 | //
37 | //
38 | //
39 |
40 | NTSTATUS uReadWrite (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
41 | {
42 | NTSTATUS Status = STATUS_SUCCESS;
43 | PIO_STACK_LOCATION Stack;
44 |
45 | Stack = IoGetCurrentIrpStackLocation( Irp );
46 |
47 | Irp->IoStatus.Status = Status;
48 | IoCompleteRequest( Irp , IO_NO_INCREMENT );
49 | return Status;
50 | }
--------------------------------------------------------------------------------
/uSCSI/SOURCES:
--------------------------------------------------------------------------------
1 | TARGETNAME=uSCSI
2 | TARGETTYPE=DRIVER
3 | TARGETPATH=..\obj
4 | TARGETLIBS=..\obj\i386\uSCSIPort.lib \
5 | $(DDK_LIB_PATH)\scsiport.lib
6 | INCLUDES=..\uSCSIPort
7 | SOURCES= uSCSI.c \
8 | IoCtl.c \
9 | Pnp.c \
10 | Utils.c \
11 | ReadWrite.c \
12 | srb.c
13 |
14 |
--------------------------------------------------------------------------------
/uSCSI/USCSI.INF:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldoldman/iSCSI_drv/e118622fa43c4756038bc72a2ef4492f807a10f8/uSCSI/USCSI.INF
--------------------------------------------------------------------------------
/uSCSI/Utils.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | //
5 | //
6 | //
7 |
8 | NTSTATUS CompletionRoutine (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,IN PVOID Context)
9 | {
10 | if (Irp->PendingReturned)
11 | {
12 | IoMarkIrpPending( Irp );
13 | KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
14 | }
15 | return STATUS_MORE_PROCESSING_REQUIRED;
16 | }
17 |
18 | //
19 | //
20 | //
21 |
22 | NTSTATUS SendIrpSynchronously (IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
23 | {
24 | KEVENT Event;
25 | NTSTATUS Status;
26 |
27 | KeInitializeEvent(&Event, NotificationEvent, FALSE);
28 |
29 | IoCopyCurrentIrpStackLocationToNext(Irp);
30 |
31 | IoSetCompletionRoutine(Irp, CompletionRoutine, &Event, TRUE, TRUE, TRUE);
32 |
33 | Status = IoCallDriver(DeviceObject, Irp);
34 | if ( STATUS_PENDING == Status )
35 | {
36 | KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL );
37 | Status = Irp->IoStatus.Status;
38 | }
39 |
40 | return Status;
41 | }
42 |
43 | //
44 | //
45 | //
46 |
47 | VOID SCSICompleteIrp(ULONG Handle, PVOID Ctx, UCHAR ScsiStatus, PUCHAR SenseData, ULONG SenseLen)
48 | {
49 | PLIST_ENTRY Ent , Ent2;
50 | PIO_STACK_LOCATION Stack;
51 | PSCSICmd Cmd;
52 | PPDO_EXT PdoExt;
53 | PSCSI_REQUEST_BLOCK Srb;
54 | BOOLEAN Found = FALSE;
55 | UCHAR ScsiOpcode;
56 | KIRQL OldIrql;
57 |
58 | PdoExt = (PPDO_EXT)Ctx;
59 | Ent = &PdoExt->CmdQueue;
60 | Ent2 = Ent->Flink;
61 |
62 | KeAcquireSpinLock ( &PdoExt->CmdQueueLock , &OldIrql );
63 |
64 | while ( Ent2 != Ent )
65 | {
66 | Cmd = CONTAINING_RECORD ( Ent2 , SCSICmd , List );
67 | if ( Cmd->Handle == Handle )
68 | {
69 | Found = TRUE;
70 | break;
71 | }
72 | Ent2 = Ent2->Flink;
73 | }
74 |
75 | if ( !Found )
76 | {
77 | KeReleaseSpinLock ( &PdoExt->CmdQueueLock , OldIrql );
78 | DbgPrint("%s Handle=0x%X Not Found!\n", __FUNCTION__ , Handle );
79 | return;
80 | }
81 |
82 | RemoveHeadList ( Cmd->List.Blink );
83 |
84 | KeReleaseSpinLock ( &PdoExt->CmdQueueLock , OldIrql );
85 |
86 | Stack = IoGetCurrentIrpStackLocation ( Cmd->Irp );
87 | Srb = Stack->Parameters.Scsi.Srb;
88 | ScsiOpcode = Srb->Cdb[0];
89 |
90 | if ( SenseData )
91 | {
92 | Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID;
93 | RtlCopyMemory ( Srb->SenseInfoBuffer , SenseData , SenseLen );
94 | }
95 | else
96 | Srb->SrbStatus = SRB_STATUS_SUCCESS;
97 |
98 | Srb->ScsiStatus = ScsiStatus;
99 | Cmd->Irp->IoStatus.Status = STATUS_SUCCESS;
100 |
101 | IoCompleteRequest ( Cmd->Irp , IO_NO_INCREMENT );
102 |
103 | ExFreePoolWithTag ( Cmd , USCSI_TAG);
104 | }
105 |
106 | //
107 | //
108 | //
109 |
110 | NTSTATUS AllocateSCSICommand ( PIRP Irp , PPDO_EXT Ext)
111 | {
112 | PIO_STACK_LOCATION Stack;
113 | PSCSICmd Cmd;
114 | PSCSI_REQUEST_BLOCK Srb;
115 | PUCHAR DataBuf;
116 | UCHAR TaskAttr , Dir , ScsiOpcode;
117 |
118 | Stack = IoGetCurrentIrpStackLocation( Irp );
119 | Srb = Stack->Parameters.Scsi.Srb;
120 | ScsiOpcode = Srb->Cdb[0];
121 |
122 | if ( Srb->QueueAction == SRB_SIMPLE_TAG_REQUEST )
123 | TaskAttr = SCSI_TASK_SIMPLE;
124 | else if ( Srb->QueueAction == SRB_HEAD_OF_QUEUE_TAG_REQUEST )
125 | TaskAttr = SCSI_TASK_HOQ;
126 | else if ( Srb->QueueAction == SRB_ORDERED_QUEUE_TAG_REQUEST)
127 | TaskAttr = SCSI_TASK_ORDERED;
128 | else
129 | TaskAttr = SCSI_TASK_UNTAGGED;
130 |
131 | if ( (Srb->SrbFlags & SRB_FLAGS_DATA_IN) && ( Srb->SrbFlags & SRB_FLAGS_DATA_OUT ))
132 | Dir = SCSI_CMD_DIR_BOTH;
133 | else if ( Srb->SrbFlags & SRB_FLAGS_DATA_IN )
134 | Dir = SCSI_CMD_DIR_READ;
135 | else if ( Srb->SrbFlags & SRB_FLAGS_DATA_OUT )
136 | Dir = SCSI_CMD_DIR_WRITE;
137 | else
138 | Dir = SCSI_CMD_DIR_NONE;
139 |
140 | //Cmd = ExAllocateFromPagedLookasideList ( &Ext->CmdLookAside );
141 | Cmd = ExAllocatePoolWithTag ( PagedPool , sizeof (SCSICmd) , USCSI_TAG);
142 | InitializeListHead ( &Cmd->List );
143 | Cmd->Irp = Irp;
144 | /*
145 | if ( ScsiOpcode == SCSIOP_READ || ScsiOpcode == SCSIOP_WRITE )
146 | DataBuf = MmGetSystemAddressForMdlSafe (Irp->MdlAddress , NormalPagePriority);
147 | else
148 | DataBuf = Srb->DataBuffer;*/
149 |
150 | if ( NULL != Irp->MdlAddress )
151 | DataBuf = MmGetSystemAddressForMdlSafe (Irp->MdlAddress , NormalPagePriority);
152 | else
153 | DataBuf = Srb->DataBuffer;
154 |
155 | ExInterlockedInsertTailList ( &Ext->CmdQueue , &Cmd->List , &Ext->CmdQueueLock);
156 | /*
157 | DbgPrint("ScsiOpcode=0x%X SrbFlags=0x%X MdlFlags=0x%X DataBuf=0x%X DataBuffer=0x%X\n" ,
158 | ScsiOpcode,
159 | Srb->SrbFlags,
160 | Irp->MdlAddress?Irp->MdlAddress->MdlFlags:0x0,
161 | DataBuf ,
162 | Srb->DataBuffer );*/
163 |
164 | uSCSIProcessSCSICmd ( Ext->Session,
165 | Srb->Cdb ,
166 | Srb->CdbLength ,
167 | DataBuf,
168 | Srb->DataTransferLength,
169 | Srb->DataTransferLength,
170 | TaskAttr,
171 | Dir,
172 | &Cmd->Handle );
173 |
174 | IoMarkIrpPending ( Irp );
175 | return STATUS_PENDING;
176 | }
177 |
178 | //
179 | //
180 | //
181 |
182 | NTSTATUS ProcessCommand (PIRP Irp , PPDO_EXT Ext)
183 | {
184 | PIO_STACK_LOCATION Stack;
185 | PCDB Cdb;
186 | UCHAR OpCode;
187 | PSCSI_REQUEST_BLOCK Srb;
188 |
189 | Stack = IoGetCurrentIrpStackLocation( Irp );
190 | Srb = Stack->Parameters.Scsi.Srb;
191 | Cdb = (PCDB)Srb->Cdb;
192 | OpCode = *((PUCHAR)Cdb);
193 |
194 | switch ( OpCode )
195 | {
196 | case SCSIOP_READ_CAPACITY: //0x25
197 | case SCSIOP_TEST_UNIT_READY: //0x00
198 | case SCSIOP_INQUIRY: //0x12
199 | case SCSIOP_MODE_SELECT: //0x15
200 | case SCSIOP_MODE_SENSE: //0x1A
201 | case SCSIOP_READ: //0x28
202 | case SCSIOP_WRITE: //0x2A
203 | case SCSIOP_VERIFY: //0x2F
204 | case SCSIOP_SYNCHRONIZE_CACHE: //0x35
205 | return AllocateSCSICommand ( Irp , Ext);
206 |
207 | default:
208 | DbgPrint("%s *** Unprocessed Opcode 0x%X\n" , __FUNCTION__ , OpCode);
209 | break;
210 | }
211 |
212 | return STATUS_SUCCESS;
213 | }
--------------------------------------------------------------------------------
/uSCSI/precomp.h:
--------------------------------------------------------------------------------
1 | #ifndef PRECOMP_H
2 | #define PRECOMP_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include "Public.h"
14 | #include "Protocol.h"
15 | #include "uSCSI.h"
16 | #include "uSCSIPort.h"
17 |
18 | #endif
19 |
--------------------------------------------------------------------------------
/uSCSI/srb.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | //
5 | // IRP_MJ_SCSI
6 | //
7 |
8 | NTSTATUS uScsi (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
9 | {
10 | NTSTATUS Status = STATUS_SUCCESS;
11 | PIO_STACK_LOCATION Stack;
12 | PPDO_EXT Ext;
13 | PSCSI_REQUEST_BLOCK Srb;
14 | PSENSE_DATA Sense;
15 | PCDB Cdb;
16 |
17 | Stack = IoGetCurrentIrpStackLocation( Irp );
18 | Ext = (PPDO_EXT)DeviceObject->DeviceExtension;
19 | Srb = Stack->Parameters.Scsi.Srb;
20 | Sense = (PSENSE_DATA)Srb->SenseInfoBuffer;
21 | Cdb = (PCDB)Srb->Cdb;
22 | /*
23 | DbgPrint("%s Srb.Function=%d SrbStatus=%d ScsiStatus=%d PathId.TargetId.Lun=%d.%d.%d QueueTag=%d QueueAction=%d CdbLength=%d SenseInfoBufferLength=%d SrbFlags=0x%X DataTransferLength=%d TimeOutValue=%d DataBuffer=0x%p SenseInfoBuffer=0x%p NextSrb=0x%p OriginalRequest=0x%p SrbExtension=0x%p cdb[0]=0x%X\n" ,
24 | __FUNCTION__ ,
25 | Srb->Function,
26 | Srb->SrbStatus,
27 | Srb->ScsiStatus,
28 | Srb->PathId,Srb->TargetId,Srb->Lun,
29 | Srb->QueueTag,
30 | Srb->QueueAction,
31 | Srb->CdbLength,
32 | Srb->SenseInfoBufferLength,
33 | Srb->SrbFlags,
34 | Srb->DataTransferLength,
35 | Srb->TimeOutValue,
36 | Srb->DataBuffer,
37 | Srb->SenseInfoBuffer,
38 | Srb->NextSrb,
39 | Srb->OriginalRequest,
40 | Srb->SrbExtension,
41 | Srb->Cdb[0]);*/
42 |
43 | // 0x01
44 | if ( SRB_FUNCTION_CLAIM_DEVICE == Srb->Function )
45 | {
46 | if (!Ext->Claimed )
47 | {
48 | Ext->Claimed = TRUE;
49 | Srb->DataBuffer = DeviceObject;
50 | }
51 | else
52 | {
53 | //Status = STATUS_DEVICE_BUSY;
54 | }
55 | }
56 | // 0x06
57 | else if ( SRB_FUNCTION_RELEASE_DEVICE == Srb->Function )
58 | {
59 | if ( Ext->Claimed )
60 | Ext->Claimed = FALSE;
61 | else
62 | Status = STATUS_UNSUCCESSFUL;
63 | }
64 | // 0x00
65 | else if ( SRB_FUNCTION_EXECUTE_SCSI == Srb->Function )
66 | {
67 | Status = ProcessCommand( Irp , Ext );
68 | if ( Status == STATUS_PENDING )
69 | return Status;
70 | }
71 | // 0x02
72 | else if ( SRB_FUNCTION_IO_CONTROL == Srb->Function )
73 | {
74 | PSRB_IO_CONTROL IoCtl;
75 | PSENDCMDOUTPARAMS OutParms;
76 | PSENDCMDINPARAMS InParms;
77 | IoCtl = Srb->DataBuffer;
78 |
79 | if ( IOCTL_SCSI_MINIPORT_IDENTIFY == IoCtl->ControlCode)
80 | {
81 | int i;
82 | InParms = (PSENDCMDINPARAMS)((PUCHAR)IoCtl + IoCtl->HeaderLength);
83 | DbgPrint(
84 | "SENDCMDINPARAMS cBufferSize=0x%X irDriveRegs=(0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X) bDriveNumber=0x%X\n" ,
85 | InParms->cBufferSize,
86 | InParms->irDriveRegs.bFeaturesReg,
87 | InParms->irDriveRegs.bSectorCountReg,
88 | InParms->irDriveRegs.bSectorNumberReg,
89 | InParms->irDriveRegs.bCylLowReg,
90 | InParms->irDriveRegs.bCylHighReg,
91 | InParms->irDriveRegs.bDriveHeadReg,
92 | InParms->irDriveRegs.bCommandReg,
93 | InParms->bDriveNumber);
94 |
95 | OutParms = (PSENDCMDOUTPARAMS)((PUCHAR)IoCtl + IoCtl->HeaderLength);
96 | DbgPrint("SENDCMDOUTPARAMS cBufferSize=0x%X\n" , OutParms->cBufferSize);
97 | //for Buffer structure refer to ATA-3 p49
98 | //
99 | OutParms->bBuffer[0] = 0x80;
100 | OutParms->bBuffer[1] = 0x40;
101 | //
102 | OutParms->bBuffer[2] = 1; //Num of logical cylinders
103 | OutParms->bBuffer[6] = 1; //Num of logical heads
104 |
105 | //10-19 Serial Number
106 | RtlCopyMemory( &OutParms->bBuffer[20] , "uSCSIDemo1234567890" , 19);
107 | // Model number
108 | for ( i = 54 ; i < 92 ; i++ )
109 | OutParms->bBuffer[i] = 'M';
110 | //Command set supported
111 | OutParms->bBuffer[164] = 0x0; //do not support
112 | OutParms->DriverStatus.bDriverError = (UCHAR)SMART_NO_ERROR;
113 | }
114 |
115 | else if ( IOCTL_SCSI_MINIPORT_ENABLE_SMART == IoCtl->ControlCode )
116 | {
117 | DbgPrint("IOCTL_SCSI_MINIPORT_ENABLE_SMART\n");
118 | }
119 |
120 | else if ( IOCTL_SCSI_MINIPORT_RETURN_STATUS == IoCtl->ControlCode )
121 | {
122 | DbgPrint("IOCTL_SCSI_MINIPORT_RETURN_STATUS\n");
123 | }
124 |
125 | else
126 | {
127 | DbgPrint("*** Unprocessed SRB_FUNCTION_IO_CONTROL HeaderLength=0x%X Signature=%c%c%c%c%c%c%c%c Timeout=0x%X ControlCode=0x%X ReturnCode=0x%X Length=0x%X\n",
128 | IoCtl->HeaderLength,
129 | IoCtl->Signature[0],IoCtl->Signature[1],IoCtl->Signature[2],IoCtl->Signature[3],
130 | IoCtl->Signature[4],IoCtl->Signature[5],IoCtl->Signature[6],IoCtl->Signature[7],
131 | IoCtl->Timeout ,
132 | IoCtl->ControlCode,
133 | IoCtl->ReturnCode,
134 | IoCtl->Length);
135 | }
136 | Irp->IoStatus.Information = 0;
137 | }
138 | // 0x07
139 | else if ( SRB_FUNCTION_SHUTDOWN == Srb->Function )
140 | {
141 | DbgPrint("TODO SRB_FUNCTION_SHUTDOWN\n");
142 | }
143 | //0x08
144 | else if ( SRB_FUNCTION_FLUSH == Srb->Function )
145 | {
146 | DbgPrint("TODO SRB_FUNCTION_FLUSH\n");
147 | }
148 | else
149 | DbgPrint("%s **** Unprocessed Srb function=0x%X CdbLength=0x%X\n" ,
150 | __FUNCTION__ , Srb->Function , Srb->CdbLength);
151 |
152 | Srb->SrbStatus = SRB_STATUS_SUCCESS;
153 |
154 | Irp->IoStatus.Status = Status;
155 | IoCompleteRequest ( Irp , IO_NO_INCREMENT );
156 | return Status;
157 | }
--------------------------------------------------------------------------------
/uSCSI/uSCSI.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | //
5 | //
6 | //
7 |
8 | NTSTATUS uAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT Pdo)
9 | {
10 | NTSTATUS Status;
11 | PDEVICE_OBJECT DevFdo;
12 | PFDO_EXT FdoExt;
13 |
14 | Status = IoCreateDevice(DriverObject,
15 | sizeof(FDO_EXT) , //user size
16 | NULL, //Name
17 | FILE_DEVICE_BUS_EXTENDER, //Device Type
18 | FILE_DEVICE_SECURE_OPEN|
19 | FILE_AUTOGENERATED_DEVICE_NAME, //Characteristics
20 | TRUE, //Exclusive
21 | &DevFdo);
22 |
23 | if ( NT_ERROR( Status ) )
24 | goto ErrorOut;
25 |
26 | FdoExt = DevFdo->DeviceExtension;
27 |
28 | FdoExt->Self = DevFdo;
29 | FdoExt->IsFDO = TRUE;
30 | FdoExt->LowerDev = IoAttachDeviceToDeviceStack( DevFdo , Pdo );
31 |
32 | FdoExt->PDOCount = 0;
33 | KeInitializeSpinLock ( &FdoExt->PDOLock );
34 | InitializeListHead ( &FdoExt->PDOList );
35 |
36 | Status = IoRegisterDeviceInterface( FdoExt->LowerDev ,
37 | &USCSI_DISK_INTERFACE,
38 | NULL,
39 | &FdoExt->InterfaceName);
40 | if ( NT_ERROR( Status ) )
41 | goto ErrorOut;
42 |
43 | DevFdo->Flags &= ~DO_DEVICE_INITIALIZING;
44 |
45 | return Status;
46 |
47 | ErrorOut:
48 |
49 | if ( DevFdo )
50 | {
51 | if (FdoExt->LowerDev)
52 | IoDetachDevice (DevFdo);
53 | IoDeleteDevice (DevFdo);
54 | }
55 | return Status;
56 | }
57 |
58 | //
59 | //
60 | //
61 |
62 | NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
63 | {
64 | NTSTATUS Status = STATUS_SUCCESS;
65 |
66 | DriverObject->DriverExtension->AddDevice = uAddDevice;
67 |
68 | DriverObject->MajorFunction[ IRP_MJ_READ ] =
69 | DriverObject->MajorFunction[ IRP_MJ_WRITE ] = uReadWrite;
70 |
71 | DriverObject->MajorFunction[ IRP_MJ_CREATE ] =
72 | DriverObject->MajorFunction[ IRP_MJ_CLOSE ] = uCreateClose;
73 |
74 | DriverObject->MajorFunction[ IRP_MJ_SCSI ] = uScsi;
75 |
76 | DriverObject->MajorFunction[ IRP_MJ_FLUSH_BUFFERS ] = uFlush;
77 | DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL] = uIoCtl;
78 | DriverObject->MajorFunction[ IRP_MJ_PNP ] = uPnP;
79 |
80 | return Status;
81 | }
--------------------------------------------------------------------------------
/uSCSI/uSCSI.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef USCSI_H
3 | #define USCSI_H
4 |
5 | #define USCSI_TAG (ULONG)'uSCI'
6 |
7 | #define FUNC_CODE(n) ((n&0x3FFC)>>2)
8 |
9 | // {BD97F566-02E4-4f6e-B29B-9B87E662A3E7}
10 | DEFINE_GUID(GUID_USCSI_BUS,
11 | 0xBD97F566,0x02E4,0x4f6e,0xB2,0x9B,0x9B,0x87,0xE6,0x62,0xA3,0xE7);
12 |
13 | #define HARDWAREID L"uSCSI\\Disk\0GenDisk\0\0"
14 | #define HARDWAREID_LEN sizeof (HARDWAREID)
15 |
16 | #define COMPATIBLEID HARDWAREID
17 | #define COMPATIBLEID_LEN HARDWAREID_LEN
18 |
19 | #define DEVICEDESC L"uSCSI Disk\0"
20 | #define DEVICEDESC_LEN sizeof(DEVICEDESC)
21 |
22 | #define DEVICEID L"uSCSI\\Disk\0"
23 | #define DEVICEID_LEN sizeof(DEVICEID)
24 |
25 | #define DEVICELOC L"uSCSI at cloud end\0"
26 | #define DEVICELOC_LEN sizeof (DEVICELOC)
27 |
28 | //
29 | //
30 | //
31 | #define DBG_SRB
32 | #define DBG_PNP
33 | #define DBG_IOCTL
34 |
35 | #define TMP_Debug( c ) \
36 | DbgPrint c
37 |
38 | #ifdef DBG_USCSI
39 | #define USCSI_Debug( c ) \
40 | DbgPrint c
41 | #else
42 | #define USCSI_Debug( c )
43 | #endif
44 |
45 | #ifdef DBG_SRB
46 | #define SRB_Debug( c ) \
47 | DbgPrint c
48 | #else
49 | #define SRB_Debug( c )
50 | #endif
51 |
52 | #ifdef DBG_PNP
53 | #define PNP_Debug( c ) \
54 | DbgPrint c
55 | #else
56 | #define PNP_Debug( c )
57 | #endif
58 |
59 | #ifdef DBG_IOCTL
60 | #define IOCTL_Debug( c ) \
61 | DbgPrint c
62 | #else
63 | #define IOCTL_Debug( c )
64 | #endif
65 |
66 | #define DPFLTR_USCSI DPFLTR_IHVDRIVER_ID
67 |
68 | #define DBG_USCSI 0x1f
69 |
70 | typedef struct _COMMON_EXT
71 | {
72 | BOOLEAN IsFDO;
73 |
74 | PDEVICE_OBJECT Self;
75 | PDEVICE_OBJECT LowerDev;
76 |
77 | }COMMON_EXT , *PCOMMON_EXT;
78 |
79 | typedef struct _FDO_EXT
80 | {
81 | COMMON_EXT;
82 |
83 | UNICODE_STRING InterfaceName;
84 |
85 | ULONG PDOCount;
86 | KSPIN_LOCK PDOLock;
87 | LIST_ENTRY PDOList;
88 |
89 | }FDO_EXT , *PFDO_EXT;
90 |
91 | typedef struct _PDO_EXT
92 | {
93 | COMMON_EXT;
94 |
95 | LIST_ENTRY PDOList;
96 |
97 | BOOLEAN Claimed;
98 | BOOLEAN Reported;
99 |
100 | PVOID Session;
101 | PUCHAR Target;
102 |
103 | PAGED_LOOKASIDE_LIST CmdLookAside;
104 |
105 | KSPIN_LOCK CmdQueueLock;
106 | LIST_ENTRY CmdQueue;
107 |
108 | }PDO_EXT , *PPDO_EXT;
109 |
110 | typedef struct _SCSICmd
111 | {
112 | LIST_ENTRY List;
113 | PIRP Irp;
114 | ULONG Handle;
115 | }SCSICmd , *PSCSICmd;
116 | //
117 | // uSCSI.c
118 | //
119 | DRIVER_INITIALIZE DriverEntry;
120 | NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath);
121 | DRIVER_ADD_DEVICE uAddDevice;
122 | NTSTATUS uAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT Pdo);
123 | //
124 | // IoCtl.c
125 | //
126 | __drv_dispatchType(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH uIoCtl;
127 | NTSTATUS uIoCtl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
128 |
129 | //
130 | // Pnp.c
131 | //
132 | __drv_dispatchType(IRP_MJ_PNP) DRIVER_DISPATCH uPnP;
133 | NTSTATUS uPnP (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
134 | //
135 | // Utils.c
136 | //
137 | IO_COMPLETION_ROUTINE CompletionRoutine;
138 | NTSTATUS CompletionRoutine (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);
139 | NTSTATUS SendIrpSynchronously (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
140 | NTSTATUS ProcessCommand (PIRP Irp , PPDO_EXT Ext);
141 |
142 | //
143 | // ReadWrite.c
144 | __drv_dispatchType(IRP_MJ_READ) DRIVER_DISPATCH uReadWrite;
145 | __drv_dispatchType(IRP_MJ_WRITE) DRIVER_DISPATCH uReadWrite;
146 | NTSTATUS uReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
147 |
148 | __drv_dispatchType(IRP_MJ_CLOSE) DRIVER_DISPATCH uCreateClose;
149 | NTSTATUS uCreateClose (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
150 |
151 | __drv_dispatchType(IRP_MJ_FLUSH_BUFFERS) DRIVER_DISPATCH uFlush;
152 | NTSTATUS uFlush (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
153 |
154 | //
155 | // Srb.c
156 | __drv_dispatchType(IRP_MJ_SCSI) DRIVER_DISPATCH uScsi;
157 | NTSTATUS uScsi (IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp);
158 | #endif
159 |
--------------------------------------------------------------------------------
/uSCSIPort/Cmd.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | PPDU PiAllocateDataOutPDU(
5 | PuCONINFO ConInfo , PUCHAR DataBuf , ULONG Offset, ULONG DataSize,PULONG DataSN, PPDU RefCmd);
6 |
7 | VOID PiDequeuePendingTask(PuCONINFO ConInfo , PPDU Pdu);
8 |
9 | __inline VOID PiSendDataOut(PuCON_CTX Ctx , PPDU CmdOrR2T );
10 |
11 | /*
12 | Process Immediate data and/or the first trunk of unsolicited data
13 |
14 | Parms:
15 | ConInfo : Connection
16 | DataBuf : Read buffer / Write Buffer / RW Buffer
17 | WriteSize :
18 | ReadSize :
19 | TaskAttr :
20 | Direction : SCSI_CMD_DIR_READ
21 | SCSI_CMD_DIR_WRITE
22 | SCSI_CMD_DIR_BOTH
23 | SCSI_CMD_DIR_NONE
24 | Return:
25 | Command PDU
26 | */
27 | PPDU PiAllocateCmdPDU (
28 | PuCONINFO ConInfo , PUCHAR DataBuf , ULONG WriteSize , ULONG ReadSize , UCHAR TaskAttr ,
29 | UCHAR Direction)
30 | {
31 | PPDU Cmd , DataOut;
32 | PSESSION Session;
33 | ULONG FirstBurstLength;
34 | ULONG MaxRecvDataSegmentLength ;
35 | ULONG ExpectedDataTansferLength , DataLen , Remaining ;
36 |
37 | FOUR_BYTE ITT;
38 |
39 | Session = ConInfo->Session;
40 |
41 | MaxRecvDataSegmentLength = KEY_TV(KV(ConInfo,KEY_MaxRecvDataSegmentLength)).Number;
42 | FirstBurstLength = KEY_FV(KV(ConInfo,KEY_FirstBurstLength)).Number;
43 |
44 | switch ( Direction )
45 | {
46 | // Read only
47 | case SCSI_CMD_DIR_READ:
48 | Cmd = TpAllocatePDU (ConInfo->ConCtx , OP_SCSI_CMD , 0 , 0 );
49 | Cmd->Bhs->SCSI_CMD.Read = 1;
50 | ExpectedDataTansferLength = ReadSize;
51 | break;
52 | // Write only
53 | case SCSI_CMD_DIR_WRITE:
54 | Cmd = TpAllocatePDU (ConInfo->ConCtx , OP_SCSI_CMD , 0 , 0 );
55 | Cmd->Bhs->SCSI_CMD.Write = 1;
56 | ExpectedDataTansferLength = WriteSize;
57 | break;
58 | // Read Write
59 | case SCSI_CMD_DIR_BOTH:
60 | Cmd = TpAllocatePDU (ConInfo->ConCtx , OP_SCSI_CMD , 8 , 0 );
61 | Cmd->Bhs->SCSI_CMD.Read = 1;
62 | Cmd->Bhs->SCSI_CMD.Write = 1;
63 | ExpectedDataTansferLength = WriteSize;
64 | break;
65 | // With no Read/Write
66 | case SCSI_CMD_DIR_NONE:
67 | Cmd = TpAllocatePDU (ConInfo->ConCtx , OP_SCSI_CMD , 0 , 0 );
68 | ExpectedDataTansferLength = 0;
69 | break;
70 | }
71 | //
72 | ITT.AsULong = InterlockedIncrement(&Session->TaskTag);
73 | REVERSE_BYTES ( &Cmd->Bhs->SCSI_CMD.InitiatorTaskTag , &ITT);
74 |
75 | Cmd->Bhs->SCSI_CMD.Attr = TaskAttr;
76 |
77 | //Write to / Read from this Buffer
78 | if (Direction != SCSI_CMD_DIR_NONE)
79 | Cmd->DataBuffer = DataBuf;
80 |
81 | /*
82 | For unidirectional operations, the Expected Data Transfer Length
83 | field contains the number of bytes of data involved in this SCSI
84 | operation. For a unidirectional write operation (W flag set to 1 and
85 | R flag set to 0), the initiator uses this field to specify the number
86 | of bytes of data it expects to transfer for this operation. For a
87 | unidirectional read operation (W flag set to 0 and R flag set to 1),
88 | the initiator uses this field to specify the number of bytes of data
89 | it expects the target to transfer to the initiator. It corresponds
90 | to the SAM2 byte count.
91 | */
92 |
93 | REVERSE_BYTES ( &Cmd->Bhs->SCSI_CMD.ExpectedDataTansferLength , &ExpectedDataTansferLength);
94 | //
95 | if ( Direction == SCSI_CMD_DIR_WRITE || Direction == SCSI_CMD_DIR_BOTH )
96 | {
97 | if ( KEY_FV(KV(ConInfo , KEY_ImmediateData)).Bool )
98 | {
99 | // Immediate data
100 | DataLen = min ( FirstBurstLength , WriteSize );
101 | DataLen = min ( DataLen , MaxRecvDataSegmentLength );
102 |
103 | REVERSE_3BYTES ( &Cmd->Bhs->SCSI_CMD.DataSegmentLength , &DataLen );
104 |
105 | Cmd->Data = DataBuf;
106 |
107 | if ( ( DataLen < WriteSize) &&
108 | ( MaxRecvDataSegmentLength < FirstBurstLength) &&
109 | !( KEY_FV(KV(ConInfo , KEY_InitialR2T)).Bool) )
110 | {
111 | // More Data in Data-Out PDU
112 | Cmd->Bhs->SCSI_CMD.Final = 0;
113 |
114 | Remaining = WriteSize - DataLen;
115 | Remaining = min (Remaining , (FirstBurstLength - DataLen));
116 |
117 | DataOut = PiAllocateDataOutPDU ( ConInfo ,
118 | DataBuf ,
119 | DataLen ,
120 | Remaining ,
121 | &Cmd->DataSN,
122 | NULL );
123 |
124 | InsertTailList ( &Cmd->DataOut , &DataOut->DataOut );
125 | }
126 | else
127 | // No More Data
128 | Cmd->Bhs->SCSI_CMD.Final = 1;
129 | }
130 | else
131 | {
132 | if ( KEY_FV(KV(ConInfo , KEY_InitialR2T)).Bool )
133 | // No Immediate data , No Unsolicited data
134 | // just wait for the R2T
135 | Cmd->Bhs->SCSI_CMD.Final = 1;
136 | else
137 | {
138 | // No Immediate data , But Unsolicited data
139 | Cmd->Bhs->SCSI_CMD.Final = 0;
140 | Remaining = min ( WriteSize , FirstBurstLength );
141 |
142 | DataOut = PiAllocateDataOutPDU ( ConInfo ,
143 | DataBuf ,
144 | 0 ,
145 | Remaining ,
146 | &Cmd->DataSN,
147 | Cmd );
148 |
149 | InsertTailList ( &Cmd->DataOut , &DataOut->DataOut );
150 | }
151 | }
152 | }
153 |
154 | if ( Direction == SCSI_CMD_DIR_READ || Direction == SCSI_CMD_DIR_NONE )
155 | {
156 | /*
157 | Setting both the W and the F bit to 0 is an error
158 |
159 | ***for read only command F bit MUST be set
160 | */
161 | Cmd->Bhs->SCSI_CMD.Final = 1;
162 | }
163 |
164 | if ( Direction == SCSI_CMD_DIR_BOTH )
165 | {
166 | PAHS Ahs;
167 | TWO_BYTE AhsLen;
168 |
169 | Ahs = (PAHS)Cmd->Ahs;
170 |
171 | AhsLen.AsUShort = 0x5;
172 | REVERSE_BYTES_SHORT ( &Ahs->AHSLength , &AhsLen );
173 |
174 | Ahs->AHSType = AHS_TYPE_BIDIR_READ_LENGTH;
175 |
176 | REVERSE_BYTES ( &Ahs->AHS_spec[1] , &ReadSize);
177 | }
178 | /*
179 | DbgPrint("%s Direction=0x%X ITT=0x%X Data=0x%p\n" ,
180 | __FUNCTION__ , Direction , ITT.AsULong , Cmd->Data);
181 | */
182 | return Cmd;
183 | }
184 |
185 | //
186 | //
187 | //
188 |
189 | BOOLEAN PiCheckCmdComplete( PPDU Cmd )
190 | {
191 | KIRQL OldIrql;
192 | BOOLEAN CanComplete = FALSE;
193 | PLIST_ENTRY DataInEnt,DataInEnt2;
194 | PPDU DataIn;
195 |
196 | if ( !(Cmd->Flags & PDU_F_CMD_CAN_COMPLETE) )
197 | goto Out;
198 | //
199 | // Check if all transfered
200 | //
201 | KeAcquireSpinLock( &Cmd->DataInOrR2TLock , &OldIrql);
202 | CanComplete = TRUE;
203 | DataInEnt = &Cmd->DataInOrR2T;
204 | DataInEnt2 = DataInEnt->Flink;
205 |
206 | while ( DataInEnt2 != DataInEnt )
207 | {
208 | DataIn = CONTAINING_RECORD ( DataInEnt2 , PDU , DataInOrR2T );
209 | if ( !(DataIn->Flags & PDU_F_DATA_IN_PROCESSED) )
210 | {
211 | CanComplete = FALSE;
212 | break;
213 | }
214 | DataInEnt2 = DataInEnt2->Flink;
215 | }
216 |
217 | KeReleaseSpinLock( &Cmd->DataInOrR2TLock ,OldIrql);
218 |
219 | Out:
220 | return CanComplete;
221 | }
222 |
223 | /*
224 | Pending command completion worker
225 |
226 | Parms:
227 | Parameter : Thread context
228 | */
229 | VOID PiPendingCompleteCmdWorker (IN PVOID Parameter)
230 | {
231 | NTSTATUS Status;
232 | PWORKER_THREAD_CTX Tctx;
233 | PSESSION Session;
234 | PuCONINFO ConInfo;
235 | PuCON_CTX Ctx;
236 | PPDU Resps , Cmd , LastDataIn;
237 | PLIST_ENTRY CmdEnt , PduEnt;
238 | UCHAR Response = 0, ScsiStatus = 0;
239 | PUCHAR SenseData = NULL;
240 | FOUR_BYTE ITT , BRC , RC;
241 | THREE_BYTE DataSegmentLength;
242 | TWO_BYTE SenseLength;
243 |
244 | Status = STATUS_SUCCESS;
245 | Tctx = (PWORKER_THREAD_CTX)Parameter;
246 | Ctx = Tctx->Ctx;
247 | ConInfo = Ctx->ConInfo;
248 | Session = ConInfo->Session;
249 |
250 | SenseLength.AsUShort = 0;
251 |
252 | while (TRUE)
253 | {
254 | Status =
255 | KeWaitForSingleObject ( &Ctx->PendingCompleteCmdEvent, Executive, KernelMode, FALSE, NULL );
256 | KeClearEvent( &Ctx->PendingCompleteCmdEvent );
257 |
258 | while ( CmdEnt = ExInterlockedRemoveHeadList(&Ctx->PendingCompleteCmds,
259 | &Ctx->PendingCompleteCmdLock))
260 | {
261 | Cmd = CONTAINING_RECORD ( CmdEnt , PDU , PendingCmd);
262 | InitializeListHead ( &Cmd->PendingCmd );
263 |
264 | REVERSE_BYTES ( &ITT , &Cmd->Bhs->STAT_FIELDS.InitiatorTaskTag );
265 |
266 | if ( Cmd->Bhs->GENERICBHS.Opcode == OP_SCSI_CMD && Cmd->Bhs->SCSI_CMD.Read )
267 | {
268 | if ( !PiCheckCmdComplete(Cmd) )
269 | {
270 | //Can't complete for now , requeue it to tail
271 | TpQueuePendingCompleteCmd ( Cmd->ConCtx , Cmd );
272 | continue;
273 | }
274 | }
275 |
276 | if ( !IsListEmpty ( &Cmd->Resps ))
277 | {
278 | //
279 | // Process Repsonse
280 | //
281 | PduEnt = RemoveHeadList ( &Cmd->Resps );
282 | Resps = CONTAINING_RECORD ( PduEnt , PDU , Resps );
283 | InitializeListHead ( &Resps->Resps );
284 |
285 | Response = Resps->Bhs->SCSI_RESPONSE.Response;
286 | ScsiStatus = Resps->Bhs->SCSI_RESPONSE.Status;
287 |
288 | KdPrintEx((DPFLTR_USCSI,DBG_PROTOCOL,
289 | "%s ITT 0x%X Resps 0x%p Response 0x%X Status 0x%X\n" ,
290 | __FUNCTION__ ,
291 | ITT.AsULong,
292 | Resps,
293 | Response ,
294 | ScsiStatus));
295 |
296 | // How to Process these residual counts ?
297 | REVERSE_BYTES ( &BRC , &Resps->Bhs->SCSI_RESPONSE.BiReadResidualCount);
298 | REVERSE_BYTES ( &RC , &Resps->Bhs->SCSI_RESPONSE.ResidualCount);
299 | //
300 | // Sense data available?
301 | //
302 | REVERSE_3BYTES (&DataSegmentLength , &Resps->Bhs->SCSI_RESPONSE.DataSegmentLength);
303 |
304 | if ( DataSegmentLength.AsULong )
305 | {
306 | REVERSE_BYTES_SHORT ( &SenseLength, Resps->Data );
307 | if (SenseLength.AsUShort)
308 | {
309 | SenseData = ExAllocatePoolWithTag ( PagedPool , SenseLength.AsUShort , USCSI_TAG);
310 | RtlCopyMemory ( SenseData , Resps->Data + 2 , SenseLength.AsUShort);
311 | }
312 | }
313 |
314 | TpQueuePduRelease( Ctx , Resps );
315 | }
316 | else
317 | {
318 | LastDataIn = CONTAINING_RECORD ( Cmd->DataInOrR2T.Blink , PDU , DataInOrR2T );
319 | ScsiStatus = LastDataIn->Bhs->SCSI_DATA_IN.Status;
320 | }
321 |
322 | (*Session->CallBack.CompleteCmd)( ITT.AsULong ,
323 | Session->CallBack.CompleteCtx ,
324 | ScsiStatus ,
325 | SenseData ,
326 | SenseLength.AsUShort );
327 | if ( SenseData )
328 | {
329 | ExFreePoolWithTag ( SenseData , USCSI_TAG);
330 | SenseData = NULL;
331 | }
332 |
333 | PiDequeuePendingTask ( ConInfo , Cmd );
334 | TpQueuePduRelease( Ctx , Cmd );
335 | }
336 | }
337 |
338 | ExFreePoolWithTag (Tctx , USCSI_TAG);
339 | }
340 |
341 | /*
342 | Allocate a iSCSI command PDU and assembly it
343 |
344 | parms:
345 | ConInfo :
346 | Cdb :
347 | CdbLength :
348 | DataBuffer :
349 | WriteSize :
350 | ReadSize :
351 | TaskAttr :
352 | Dir :
353 |
354 | return:
355 | iSCSI command PDU
356 | */
357 |
358 | PPDU PtAssembleSCSICmd
359 | (PuCONINFO ConInfo, PUCHAR Cdb, ULONG CdbLength, PUCHAR DataBuffer,
360 | ULONG WriteSize, ULONG ReadSize, UCHAR TaskAttr, UCHAR Dir )
361 | {
362 | PPDU Cmd;
363 |
364 | Cmd = PiAllocateCmdPDU ( ConInfo , DataBuffer , WriteSize , ReadSize , TaskAttr, Dir );
365 |
366 | if( NULL != Cmd )
367 | RtlCopyMemory ( Cmd->Bhs->SCSI_CMD.Cdb , Cdb , min (16, CdbLength) );
368 |
369 | return Cmd;
370 | }
--------------------------------------------------------------------------------
/uSCSIPort/Data.c:
--------------------------------------------------------------------------------
1 | #include "precomp.h"
2 |
3 | PPDU PiFindPendingTask(ULONG TaskTag , PuCONINFO ConInfo , BOOLEAN Remove);
4 |
5 | PPDU PiQueueDataInOrR2T(PuCONINFO ConInfo , PPDU Task , PPDU DataIn);
6 |
7 | //
8 | //
9 | //
10 |
11 | BOOLEAN PiCheckDataInHole ( PPDU Cmd )
12 | {
13 | PLIST_ENTRY DataOrR2TEnt , DataOrR2TEnt2 ,DataOrR2TEnt3 , Last2ndEnt;
14 | PPDU DataOrR2T2 , DataOrR2T3;
15 | FOUR_BYTE DataSN2 , DataSN3;
16 | ULONG Gap = 0;
17 | BOOLEAN Hole = FALSE ;
18 |
19 | DataOrR2TEnt = &Cmd->DataInOrR2T;
20 |
21 | return FALSE; //Temp for test purpose
22 |
23 | if ( !Cmd->ExpDataSN )
24 | return Hole;
25 |
26 | if ( DataOrR2TEnt->Flink == DataOrR2TEnt )
27 | {
28 | // Zero
29 | while ( Gap < Cmd->ExpDataSN )
30 | {
31 | Hole = TRUE;
32 | Cmd->Flags |= PDU_F_DATA_IN_RETRANSMIT;
33 | Gap++;
34 | }
35 | }
36 |
37 | else if ( DataOrR2TEnt->Flink->Flink == DataOrR2TEnt )
38 | {
39 | // Just one
40 | DataOrR2TEnt2 = DataOrR2TEnt->Flink;
41 | DataOrR2T2 = CONTAINING_RECORD ( DataOrR2TEnt2 , PDU , DataInOrR2T);
42 | REVERSE_BYTES ( &DataSN2 , &DataOrR2T2->Bhs->STAT_FIELDS.DataSN );
43 |
44 | if ( Cmd->ExpDataSN )
45 | {
46 | Hole = TRUE;
47 | Cmd->Flags |= PDU_F_DATA_IN_RETRANSMIT;
48 | while ( Gap < DataSN2.AsULong )
49 | {
50 | //
51 | Gap++;
52 | }
53 |
54 | Gap = DataSN2.AsULong + 1;
55 | while ( Gap <= Cmd->ExpDataSN )
56 | {
57 | //
58 | Gap++;
59 | }
60 | }
61 | }
62 |
63 | else
64 | {
65 | // At least two
66 | Last2ndEnt = DataOrR2TEnt->Blink->Blink;
67 | DataOrR2TEnt2 = DataOrR2TEnt->Flink;
68 | DataOrR2TEnt3 = DataOrR2TEnt2->Flink;
69 |
70 | while ( TRUE )
71 | {
72 | DataOrR2T2 = CONTAINING_RECORD ( DataOrR2TEnt2 , PDU , DataInOrR2T);
73 | DataOrR2T3 = CONTAINING_RECORD ( DataOrR2TEnt3 , PDU , DataInOrR2T);
74 |
75 | REVERSE_BYTES ( &DataSN2 , &DataOrR2T2->Bhs->STAT_FIELDS.DataSN);
76 | REVERSE_BYTES ( &DataSN3 , &DataOrR2T3->Bhs->STAT_FIELDS.DataSN);
77 | //
78 | // First DataSN MUST Start with 0
79 | //
80 | if ( DataOrR2TEnt2->Blink == DataOrR2TEnt && DataSN2.AsULong )
81 | {
82 | Hole = TRUE;
83 | Cmd->Flags |= PDU_F_DATA_IN_RETRANSMIT;
84 | while ( Gap < DataSN2.AsULong )
85 | {
86 | // Request the missing Data-In(s)
87 | Gap++;
88 | }
89 | }
90 |
91 | if ( DataSN2.AsULong + 1 != DataSN3.AsULong )
92 | {
93 | Hole = TRUE;
94 | Cmd->Flags |= PDU_F_DATA_IN_RETRANSMIT;
95 |
96 | Gap = DataSN2.AsULong + 1;
97 | while ( Gap < DataSN3.AsULong )
98 | {
99 | // Request the missing Data-In(s)
100 | Gap++;
101 | }
102 | }
103 |
104 | if ( DataOrR2TEnt2 == Last2ndEnt && DataSN3.AsULong != Cmd->ExpDataSN )
105 | {
106 | Hole = TRUE;
107 | Cmd->Flags |= PDU_F_DATA_IN_RETRANSMIT;
108 | Gap = DataSN3.AsULong + 1;
109 | while ( Gap < Cmd->ExpDataSN )
110 | {
111 | //
112 | Gap++;
113 | }
114 | break;
115 | }
116 | else
117 | {
118 | DataOrR2TEnt2 = DataOrR2TEnt2->Flink;
119 | DataOrR2TEnt3 = DataOrR2TEnt2->Flink;
120 | }
121 | }
122 | }
123 |
124 | return Hole;
125 | }
126 |
127 | /*
128 | ConCtx |-----------------|---------|--> Cmd1
129 | | | | |
130 | |_R2Ts - R2T1.2 - R2T2.2 - R2T1.4 - R2T1.5 - R2T2.3
131 | | | |
132 | | |--------------------------|-->Cmd2
133 | |
134 | | |--------|-----------------|--> Cmd1
135 | | | | |
136 | |_DataIns - Di1.1 - Di1.3 - Di2.1 - Di1.6 - Di2.4
137 | | |
138 | |------------------|-->Cmd2
139 |
140 | R2T / Data-In link in 2 queues
141 | 1. R2Ts or DataIns queue of connection by PDUList
142 | 2. SCSI Cmd's DataInOrR2T queue by DataInOrR2T
143 |
144 | R2Ts queue is served by R2TWorker
145 | DataIns queue is served by DataInWorker
146 |
147 | */
148 | /*
149 | 1. Insert Data-in PDU into a Per-Cmd List , sorted by DataSN
150 | 2. Check PDU Final bit , if set , trigger Data-in PDUs process
151 | */
152 | VOID PtProcessDataIn (PPDU Pdu, PuCONINFO ConInfo)
153 | {
154 | PPDU Cmd;
155 | PPDU DataAck;
156 | PuCON_CTX Ctx;
157 | FOUR_BYTE DataSN , DataSize , Offset , ITT;
158 |
159 | Ctx = ConInfo->ConCtx;
160 |
161 | REVERSE_BYTES ( &ITT , &Pdu->Bhs->SCSI_DATA_IN.InitiatorTaskTag );
162 |
163 | Cmd = PiFindPendingTask ( ITT.AsULong , ConInfo , FALSE);
164 | if ( !Cmd )
165 | {
166 | DbgPrint( "No Matching Command for DataIn %x (ITT 0x%x)\n", Pdu , ITT.AsULong);
167 | TpQueuePduRelease( Ctx , Pdu );
168 | goto Out;
169 | }
170 |
171 | Pdu->Cmd = Cmd;
172 |
173 | KdPrintEx((DPFLTR_USCSI , DBG_PROTOCOL ,
174 | "%s ITT 0x%X Pdu 0x%p FSUO %d%d%d%d\n" ,
175 | __FUNCTION__ ,
176 | ITT.AsULong ,
177 | Pdu,
178 | Pdu->Bhs->SCSI_DATA_IN.Final,
179 | Pdu->Bhs->SCSI_DATA_IN.S,
180 | Pdu->Bhs->SCSI_DATA_IN.U,
181 | Pdu->Bhs->SCSI_DATA_IN.O ));
182 |
183 | // Pdu maybe dropped by PiQueueDataInOrR2T
184 | // in which case PiQueueDataInOrR2T return NULL
185 | // else return the orignal Pdu
186 |
187 | Pdu = PiQueueDataInOrR2T ( ConInfo , Cmd , Pdu );
188 |
189 | if ( !Pdu )
190 | goto Out;
191 |
192 | //
193 | // Queue to Copy data
194 | //
195 | TpQueueDataInPDU ( Ctx , Pdu );
196 |
197 | if (KEY_FV(KV(ConInfo,KEY_ErrorRecoveryLevel)).Number >0 &&
198 | Pdu->Bhs->SCSI_DATA_IN.Ack)
199 | {
200 | /*
201 | The initiator MUST ignore the A bit set to 1 for sessions with
202 | ErrorRecoveryLevel=0.
203 | */
204 | // Allocate a DataAck
205 | DataAck = TpAllocatePDU ( Ctx , OP_SNACK_REQ , 0 , 0 );
206 | RtlCopyMemory ( &DataAck->Bhs->SNACK.TargetTransferTag,
207 | &Pdu->Bhs->SCSI_DATA_IN.TargetTransferTag,
208 | 4);
209 | //...
210 | TpQueueOutPDU (Ctx , DataAck);
211 | }
212 |
213 | if ( Pdu->Bhs->SCSI_DATA_IN.Final)
214 | {
215 | // Trigger Data Sequence checking
216 | /*
217 | Status can accompany the last Data-In PDU if the command did not end
218 | with an exception (i.e., the status is "good status" - GOOD,
219 | CONDITION MET or INTERMEDIATE CONDITION MET). The presence of status
220 | (and of a residual count) is signaled though the S flag bit.
221 | */
222 | if ( Pdu->Bhs->SCSI_DATA_IN.S )
223 | {
224 | REVERSE_BYTES ( &DataSN , &Pdu->Bhs->SCSI_DATA_IN.DataSN);
225 | Cmd->ExpDataSN = DataSN.AsULong;
226 |
227 | if ( !PiCheckDataInHole ( Cmd ) )
228 | {
229 | //DbgPrint("CompleteCmd=0x%X\n",Cmd);
230 | Cmd->Flags |= PDU_F_CMD_CAN_COMPLETE;
231 | TpQueuePendingCompleteCmd ( Ctx , Cmd );
232 | }
233 | }
234 | }
235 | else if ( (Cmd->Flags & PDU_F_DATA_IN_RETRANSMIT) && !PiCheckDataInHole ( Cmd ) )
236 | {
237 | KdPrintEx((DPFLTR_USCSI , DBG_PROTOCOL ,"%s Debug\n" , __FUNCTION__ ));
238 | TpQueuePendingCompleteCmd ( ConInfo->ConCtx , Cmd );
239 | }
240 |
241 | Out:
242 |
243 | return;
244 | }
245 | /*
246 | Insert Data-in / R2T PDU sorted by DataSN
247 | Parms
248 | Cmd : to which DataInOrR2T belong
249 | DataInOrR2T : Data-in / R2T
250 | Return
251 | NULL , if this is a duplicated Data-In
252 | DataIn , the original DataIn
253 | */
254 | PPDU PiQueueDataInOrR2T(PuCONINFO ConInfo, PPDU Cmd, PPDU DataInOrR2T)
255 | {
256 | KIRQL OldIrql;
257 | PLIST_ENTRY DataInEnt , DataInEnt2;
258 | FOUR_BYTE Num , Num2;
259 | PPDU DataIn2;
260 |
261 | KeAcquireSpinLock( &Cmd->DataInOrR2TLock, &OldIrql);
262 | DataInEnt = &Cmd->DataInOrR2T;
263 | REVERSE_BYTES ( &Num , &DataInOrR2T->Bhs->STAT_FIELDS.DataSN);
264 |
265 | DataInEnt2 = DataInEnt->Flink;
266 |
267 | while ( DataInEnt2 != DataInEnt )
268 | {
269 | DataIn2 = CONTAINING_RECORD ( DataInEnt2 , PDU , DataInOrR2T );
270 |
271 | REVERSE_BYTES ( &Num2 , &DataIn2->Bhs->STAT_FIELDS.DataSN );
272 |
273 | if ( Num2.AsULong < Num.AsULong )
274 | break;
275 | else if ( Num2.AsULong == Num.AsULong)
276 | {
277 | KeReleaseSpinLock( &Cmd->DataInOrR2TLock, OldIrql);
278 | // Duplicated Data-In
279 | // Drop it?
280 | DbgPrint("Duplicated DataIn=0x%X Droped\n",DataInOrR2T);
281 | Cmd->DupDataInCount++;
282 | TpQueuePduRelease( ConInfo->ConCtx , DataInOrR2T );
283 | return NULL;
284 | }
285 | DataInEnt2 = DataInEnt2->Flink;
286 | }
287 |
288 | DataInEnt = &DataInOrR2T->DataInOrR2T;
289 |
290 | InsertHeadList ( DataInEnt2 , DataInEnt);
291 | KeReleaseSpinLock( &Cmd->DataInOrR2TLock, OldIrql);
292 |
293 | return DataInOrR2T;
294 | }
295 |
296 | //
297 | //
298 | //
299 |
300 | VOID PiDataInWorker(IN PVOID Parameter)
301 | {
302 | NTSTATUS Status;
303 | PWORKER_THREAD_CTX Tctx;
304 | PSESSION Session;
305 | PuCONINFO ConInfo;
306 | PuCON_CTX Ctx;
307 | PLIST_ENTRY DataInEnt , DataInEnt2;
308 | PPDU DataIn , Cmd;
309 | ULONG BufferOffset;
310 | THREE_BYTE DataSegmentLength;
311 | FOUR_BYTE ITT;
312 | BOOLEAN AllTransfered;
313 |
314 | Status = STATUS_SUCCESS;
315 | Tctx = (PWORKER_THREAD_CTX)Parameter;
316 | Ctx = Tctx->Ctx;
317 | ConInfo = Ctx->ConInfo;
318 | Session = ConInfo->Session;
319 |
320 | while (TRUE)
321 | {
322 | Status =
323 | KeWaitForSingleObject (&Ctx->DataInEvent, Executive, KernelMode, FALSE, NULL);
324 | KeClearEvent( &Ctx->DataInEvent );
325 |
326 | while ( DataInEnt = ExInterlockedRemoveHeadList ( &Ctx->DataIns , &Ctx->DataInLock ) )
327 | {
328 | DataIn = CONTAINING_RECORD ( DataInEnt , PDU , PDUList );
329 | InitializeListHead ( &DataIn->PDUList);
330 |
331 | Cmd = DataIn->Cmd;
332 | /*
333 | {
334 | LARGE_INTEGER Tick;
335 | KeQueryTickCount( &Tick);
336 | DbgPrint("%s Time=0x%X-%X Cmd=0x%X Pdu=0x%X Bhs=0x%X\n" ,
337 | __FUNCTION__ , Tick.HighPart,Tick.LowPart , Cmd , DataIn,DataIn->Bhs);
338 | }*/
339 | REVERSE_BYTES ( &ITT , &DataIn->Bhs->SCSI_DATA_IN.InitiatorTaskTag);
340 | REVERSE_3BYTES ( &DataSegmentLength , &DataIn->Bhs->SCSI_DATA_IN.DataSegmentLength);
341 | REVERSE_BYTES ( &BufferOffset , &DataIn->Bhs->SCSI_DATA_IN.BufferOffset );
342 | /*
343 | DbgPrint(
344 | "%s Cmd=0x%X ITT=0x%X DataBuffer=0x%p Offset=0x%X Length=0x%X Data=0x%X S=0x%X Final=0x%X\n",
345 | __FUNCTION__,
346 | Cmd,
347 | ITT.AsULong,
348 | Cmd->DataBuffer,
349 | BufferOffset,
350 | DataSegmentLength.AsULong,
351 | DataIn->Data,
352 | DataIn->Bhs->SCSI_DATA_IN.S,
353 | DataIn->Bhs->SCSI_DATA_IN.Final);*/
354 | // Copy Data
355 | if (Cmd->DataBuffer)
356 | RtlCopyMemory( Cmd->DataBuffer + BufferOffset,
357 | DataIn->Data,
358 | DataSegmentLength.AsULong );
359 |
360 | DataIn->Flags |= PDU_F_DATA_IN_PROCESSED;
361 | }
362 | }
363 |
364 | ExFreePoolWithTag (Tctx , USCSI_TAG);
365 | }
366 |
367 | //
368 | // DataBuf : Data Buffer
369 | // Offset : Offset
370 | // DataSize: Data size count from Offset
371 | // for Unsolicited data , DataSize range is (0 , FirstBurstLength]
372 | // for Solicited data , DataSize range is (0 , MaxBurstLength]
373 | /*
374 | ----------
375 | /|\
376 | |
377 | |
378 | DataSize
379 | |
380 | |
381 | \|/
382 | ---------- <- Offset
383 | /|\
384 | |
385 | |
386 | \|/
387 | ---------- <- DataBuf
388 |
389 | */
390 |
391 | PPDU PiAllocateDataOutPDU(
392 | PuCONINFO ConInfo, PUCHAR DataBuf, ULONG Offset, ULONG DataSize, PULONG DataSN, PPDU RefCmd)
393 | {
394 | ULONG DataLen , MaxRecvDataSegmentLength;
395 | PPDU DataOut = NULL , Tmp ;
396 | PLIST_ENTRY Ent;
397 |
398 | MaxRecvDataSegmentLength = KEY_TV(KV(ConInfo,KEY_MaxRecvDataSegmentLength)).Number;
399 |
400 | do
401 | {
402 | DataLen = min (DataSize , MaxRecvDataSegmentLength);
403 |
404 | Tmp = TpAllocatePDU ( ConInfo->ConCtx , OP_DATA_OUT , 0 , 0 );
405 |
406 | if ( !Tmp )
407 | goto ErrorOut;
408 | else if ( DataOut )
409 | InsertTailList ( &DataOut->DataOut , &Tmp->DataOut );
410 | else
411 | DataOut = Tmp;
412 |
413 | Tmp->Bhs->SCSI_DATA_OUT.Final = 0;
414 |
415 | REVERSE_3BYTES ( &Tmp->Bhs->SCSI_DATA_OUT.DataSegmentLength , &DataLen );
416 | REVERSE_BYTES ( &Tmp->Bhs->SCSI_DATA_OUT.BufferOffset , &Offset);
417 |
418 | *DataSN++;
419 | REVERSE_BYTES ( &Tmp->Bhs->SCSI_DATA_OUT.DataSN , DataSN);
420 |
421 | RtlCopyMemory ( &Tmp->Bhs->SCSI_DATA_OUT.InitiatorTaskTag ,
422 | &RefCmd->Bhs->GENERICBHS.InitiatorTaskTag ,
423 | 4);
424 |
425 | if ( RefCmd->Bhs->GENERICBHS.Opcode == OP_R2T )
426 | RtlCopyMemory ( &Tmp->Bhs->SCSI_DATA_OUT.TargetTansferTag ,
427 | &RefCmd->Bhs->R2T.TargetTansferTag ,
428 | 4);
429 |
430 | Tmp->Data = DataBuf + Offset;
431 |
432 | Offset += DataLen;
433 | DataSize -= DataLen; // DataSize will NEVER < 0
434 |
435 | }while ( DataSize > 0);
436 |
437 | Tmp->Bhs->SCSI_DATA_OUT.Final = 1;
438 |
439 | return DataOut;
440 |
441 | ErrorOut:
442 |
443 | if (DataOut)
444 | //TpFreePDU( ConInfo->ConCtx , DataOut , 0 );
445 | TpQueuePduRelease( ConInfo->ConCtx , DataOut );
446 |
447 | return NULL;
448 | }
449 | /*
450 | Send DataOut Queue of command
451 | if this is a SCSI command with unsolicited data
452 | SCSI command MUST be sent first
453 | */
454 | VOID PiSendDataOut(PuCON_CTX Ctx , PPDU CmdOrR2T )
455 | {
456 | PPDU DataOut;
457 | PLIST_ENTRY PduEnt , PduEnt2;
458 |
459 | PduEnt = &CmdOrR2T->DataOut;
460 | PduEnt2 = PduEnt->Flink;
461 |
462 | while ( PduEnt2 != PduEnt )
463 | {
464 | DataOut = CONTAINING_RECORD ( PduEnt2 , PDU , DataOut );
465 | TpQueueOutPDU( Ctx , DataOut );
466 | PduEnt2 = PduEnt2->Flink;
467 | }
468 | }
469 |
470 |
--------------------------------------------------------------------------------
/uSCSIPort/Discover.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 |
--------------------------------------------------------------------------------
/uSCSIPort/Handler.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | //Key Handlers
5 |
6 | VOID PiUpdateKeyNegoState ( KEY_NAME Key , PuCONINFO ConInfo , PLIST_ENTRY Answers);
7 | ULONG PiGetKeyState ( KEY_NAME Key , PuCONINFO ConInfo );
8 | VOID PiSetKeyState ( KEY_NAME Key , PuCONINFO ConInfo , UCHAR State);
9 | PKEY_VALUE PiFormatKeyValue (PKEY_VALUE Val);
10 |
11 | VOID PiHandleReject (
12 | PKEY_VALUE KeyVal , PuCONINFO ConInfo , PLIST_ENTRY Questions , PLIST_ENTRY Answers )
13 | {
14 | KEY_NAME Key;
15 | Key = KeyVal->Key.D;
16 |
17 | PROT_Debug(("%s Reject\n" , PiKeyName(Key)));
18 | // Assert ( PiGetKeyState(KeyVal->Key.D , ConInfo) == KEY_Proposed )
19 | KV(ConInfo , Key)->Flags |= KEY_Reject;
20 |
21 | PiSetKeyState ( Key , ConInfo , KEY_Defaulted );
22 | }
23 |
24 | VOID PiHandleIrrelevant (
25 | PKEY_VALUE KeyVal , PuCONINFO ConInfo , PLIST_ENTRY Questions , PLIST_ENTRY Answers )
26 | {
27 | KEY_NAME Key;
28 | Key = KeyVal->Key.D;
29 |
30 | PROT_Debug(("%s Irrelevant\n" , PiKeyName(Key)));
31 | // Assert ( PiGetKeyState(KeyVal->Key.D , ConInfo) == KEY_Proposed )
32 | KV(ConInfo,Key)->Flags |= KEY_Irrelevant;
33 | PiSetKeyState ( Key , ConInfo , KEY_Defaulted );
34 | }
35 |
36 | VOID PiHandleNone (
37 | PKEY_VALUE KeyVal , PuCONINFO ConInfo , PLIST_ENTRY Questions , PLIST_ENTRY Answers )
38 | {
39 | PSESSION Session;
40 | KEY_NAME Key;
41 | Session = ConInfo->Session;
42 | Key = KeyVal->Key.D;
43 |
44 | PROT_Debug(("%s None\n" , PiKeyName(Key)));
45 |
46 | if ( PiKeys[Key].Attrs & KEY_TYPE_LOV )
47 | {
48 | KV(ConInfo , Key)->Flags |= KEY_None;
49 | PiUpdateKeyNegoState ( Key , ConInfo , Answers );
50 | //PiSetKeyState ( Key , ConInfo , KEY_Agreed );
51 | }
52 | else
53 | {
54 | PROT_Debug(("%s Protocol Error\n" , __FUNCTION__));
55 | PiSetKeyState ( Key , ConInfo , KEY_Defaulted );
56 | }
57 | }
58 |
59 | VOID PiHandleNotUnderstood (
60 | PKEY_VALUE KeyVal , PuCONINFO ConInfo , PLIST_ENTRY Questions , PLIST_ENTRY Answers )
61 | {
62 | KEY_NAME Key;
63 | Key = KeyVal->Key.D;
64 |
65 | PROT_Debug(("%s NotUnderstood\n" ,KeyVal->Key.U , KEY_FV(KeyVal).String));
66 | /*
67 | KV(ConInfo , Key)->Flags |= KEY_NotUnderstood;
68 |
69 | PiSetKeyState ( Key , ConInfo , KEY_Defaulted );*/
70 | }
71 |
72 |
73 |
74 | VOID PiHandleIllegal (
75 | PKEY_VALUE KeyVal , PuCONINFO ConInfo , PLIST_ENTRY Questions , PLIST_ENTRY Answers )
76 | {
77 | PKEY_VALUE Kv;
78 | KEY_VALUE Kv2 = {0};
79 | KEY_NAME Key;
80 |
81 | Key = KeyVal->Key.D;
82 | PROT_Debug(("%s Illegal\n" , PiKeyName(Key)));
83 | //Mark Reject
84 | KeyVal->Flags &= ~KEY_Illegal;
85 | KeyVal->Flags |= KEY_Reject;
86 |
87 | Kv = PiFormatKeyValue ( KeyVal );
88 | InsertTailList ( Answers , &Kv->Vals);
89 | }
90 |
91 |
92 | VOID PiHandleDeclarative (
93 | PKEY_VALUE KeyVal , PuCONINFO ConInfo , PLIST_ENTRY Questions , PLIST_ENTRY Answers)
94 | {
95 | ULONG TLen , ILen;
96 | PUCHAR Tmp;
97 | KEY_NAME Key;
98 | PKEY_VALUE Kv , *Kv2 , Kv3;
99 |
100 | Key = KeyVal->Key.D;
101 | if ( Key == KEY_TargetAlias ) return;//temp
102 | Kv = KV(ConInfo , Key);
103 | Kv2 = AddrKV(ConInfo , Key);
104 |
105 | if (PiIsKeyBool(Key))
106 | {
107 | KEY_TV(Kv).Bool = KEY_FV(KeyVal).Bool;
108 | PROT_Debug (("Boolean 0x%X accepted\n" , KEY_TV(Kv).Bool));
109 | }
110 | else if ( PiIsKeyNumber(Key))
111 | {
112 | KEY_TV(Kv).Number = KEY_FV(KeyVal).Number;
113 | PROT_Debug (("Number 0x%X accepted\n" , KEY_TV(Kv).Number));
114 | }
115 | else if ( PiIsKeyString(Key))
116 | {
117 | TLen = strlen ( KEY_FV(KeyVal).String );
118 | if (TLen)
119 | {
120 | ILen = strlen ( Kv->Value[KEY_I].String );
121 | if ( ILen)
122 | {
123 | Kv3 = PiAllocateKeyValStr( ILen + 1 , TLen + 1 );
124 | Tmp = KEY_IV(Kv3).String;
125 | RtlCopyMemory ( Kv3 , Kv , sizeof (KEY_VALUE) + ILen + 1);
126 | KEY_IV(Kv3).String = Tmp;
127 | }
128 | else
129 | {
130 | Kv3 = PiAllocateKeyValStr1( TLen + 1 );
131 | RtlCopyMemory ( Kv3 , Kv , sizeof (KEY_VALUE));
132 | }
133 | RtlCopyMemory ( KEY_TV(Kv3).String , KEY_FV(KeyVal).String , TLen + 1);
134 | ExFreePoolWithTag (Kv , USCSI_TAG);
135 | *Kv2 = Kv3;
136 | PROT_Debug (("String '%s' accepted\n" , KEY_TV(Kv3).String));
137 | }
138 | }
139 | else if (PiIsKeyLov(Key))
140 | {
141 | TLen = strlen ( KEY_FV(KeyVal).Lov.Val );
142 | if (TLen)
143 | {
144 | ILen = strlen ( Kv->Value[KEY_I].Lov.Val );
145 | if ( ILen)
146 | {
147 | Kv3 = PiAllocateKeyValStr( ILen + 1 , TLen + 1 );
148 | Tmp = KEY_IV(Kv3).Lov.Val;
149 | RtlCopyMemory ( Kv3 , Kv , sizeof (KEY_VALUE) + ILen + 1);
150 | KEY_IV(Kv3).String = Tmp;
151 | }
152 | else
153 | {
154 | Kv3 = PiAllocateKeyValStr1( TLen + 1 );
155 | RtlCopyMemory ( Kv3 , Kv , sizeof (KEY_VALUE));
156 | }
157 | RtlCopyMemory ( KEY_TV(Kv3).Lov.Val , KEY_FV(KeyVal).Lov.Val , TLen + 1);
158 | ExFreePoolWithTag (Kv , USCSI_TAG);
159 | *Kv2 = Kv3;
160 | PROT_Debug (("Lov '%s' accepted\n" , KEY_TV(Kv3).Lov.Val));
161 | }
162 | }
163 | }
164 | /*
165 | Handler for most predefined Keys
166 | */
167 | VOID PiInternalHandler (
168 | PKEY_VALUE KeyVal , PuCONINFO ConInfo , PLIST_ENTRY Questions , PLIST_ENTRY Answers )
169 | {
170 | PSESSION Session;
171 | KEY_NAME Key;
172 | PKEY_VALUE Kv, *Kv2 , Kv3;
173 |
174 | Session = ConInfo->Session;
175 | Key = KeyVal->Key.D;
176 |
177 | PROT_Debug(("%s " , PiKeyName(Key)));
178 |
179 | Kv = KV(ConInfo , Key);
180 | Kv2 = AddrKV(ConInfo , Key);
181 |
182 | if ( PiIsKeyDeclarative( Key ) )
183 | {
184 | PiHandleDeclarative(KeyVal , ConInfo , Questions , Answers);
185 | return;
186 | }
187 |
188 | // Answer value is Reject
189 | if ( KeyVal->Flags & KEY_Reject )
190 | PiHandleReject( KeyVal , ConInfo , Questions , Answers );
191 | // Answer value is Irrelevant
192 | else if ( KeyVal->Flags & KEY_Irrelevant )
193 | PiHandleIrrelevant( KeyVal , ConInfo , Questions , Answers );
194 | // Answer value is None
195 | else if ( KeyVal->Flags & KEY_None )
196 | PiHandleNone ( KeyVal , ConInfo , Questions , Answers );
197 | // only for incoming Keys
198 | // Answer value is "NotUnderstood"
199 | else if ( KeyVal->Flags & KEY_NotUnderstood )
200 | PiHandleNotUnderstood (KeyVal , ConInfo , Questions , Answers );
201 | // Value is Illegal , for example , out of range
202 | else if ( KeyVal->Flags & KEY_Illegal)
203 | PiHandleIllegal( KeyVal , ConInfo , Questions , Answers );
204 |
205 | else if ( PiIsKeyBool(Key) )
206 | {
207 | if ( PiKeys[Key].Attrs & KEY_FUNC_OR )
208 | KEY_PV(Kv).Bool = KEY_FV(Kv).Bool | KEY_FV(KeyVal).Bool;
209 | else if ( PiKeys[Key].Attrs & KEY_FUNC_AND )
210 | KEY_PV(Kv).Bool = KEY_FV(Kv).Bool & KEY_FV(KeyVal).Bool;
211 | PROT_Debug (("Boolean 0x%X->0x%X\n" , KEY_FV(Kv).Bool , KEY_PV(Kv).Bool));
212 | }
213 | else if ( PiIsKeyNumber(Key) )
214 | {
215 | if ( PiKeys[Key].Attrs & KEY_FUNC_MIN )
216 | KEY_PV(Kv).Number = min ( KEY_FV(Kv).Number , KEY_FV(KeyVal).Number);
217 | else if ( PiKeys[Key].Attrs & KEY_FUNC_MAX )
218 | KEY_PV(Kv).Number = max ( KEY_FV(Kv).Number , KEY_FV(KeyVal).Number);
219 | PROT_Debug (("Number 0x%X->0x%X\n" , KEY_FV(Kv).Number , KEY_PV(Kv).Number));
220 | }
221 | else if ( PiIsKeyString(Key) )
222 | {
223 | PUCHAR Tmp , Tmp2;
224 | ULONG PLen , FLen , Tmp3;
225 | PLen = strlen ( KEY_FV(KeyVal).String );
226 | if (PLen)
227 | {
228 | FLen = strlen ( KEY_FV(Kv).String);
229 | if (FLen)
230 | {
231 | Kv3 = PiAllocateKeyValStr( FLen + 1, PLen + 1 );
232 | Tmp = KEY_FV(Kv3).String;
233 | Tmp2 = KEY_PV(Kv3).String;
234 | Tmp3 = Kv3->Size;
235 |
236 | RtlCopyMemory ( Kv3 , Kv , sizeof (KEY_VALUE) );
237 |
238 | KEY_FV(Kv3).String = Tmp;
239 | RtlCopyMemory ( KEY_FV(Kv3).String , KEY_FV(Kv).String , FLen + 1);
240 |
241 | KEY_PV(Kv3).String = Tmp2;
242 | Kv3->Size = Tmp3;
243 |
244 | }
245 | else
246 | {
247 | Kv3 = PiAllocateKeyValStr1( PLen + 1 );
248 | Tmp2 = KEY_PV(Kv3).String;
249 | Tmp3 = Kv3->Size;
250 |
251 | RtlCopyMemory ( Kv3 , Kv , sizeof (KEY_VALUE) );
252 |
253 | KEY_PV(Kv3).String = Tmp2;
254 | Kv3->Size = Tmp3;
255 | }
256 |
257 | RtlCopyMemory ( KEY_PV(Kv3).String , KEY_FV(KeyVal).String , PLen + 1);
258 |
259 | PROT_Debug (("String 0x%X->0x%X\n" , KEY_FV(Kv).String , KEY_PV(Kv).String));
260 | }
261 | }
262 | else if ( PiIsKeyLov(Key) )
263 | {
264 | PUCHAR Tmp , Tmp2;
265 | ULONG PLen , FLen , Tmp3;
266 | PLen = strlen ( KEY_FV(KeyVal).Lov.Val );
267 | if (PLen)
268 | {
269 | FLen = strlen ( KEY_FV(Kv).Lov.Val);
270 | if (FLen)
271 | {
272 | Kv3 = PiAllocateKeyValStr( FLen + 1, PLen + 1 );
273 | Tmp = KEY_FV(Kv3).Lov.Val;
274 | Tmp2 = KEY_PV(Kv3).Lov.Val;
275 | Tmp3 = Kv3->Size;
276 |
277 | RtlCopyMemory ( Kv3 , Kv , sizeof (KEY_VALUE) );
278 |
279 | KEY_FV(Kv3).Lov.Val = Tmp;
280 | RtlCopyMemory ( KEY_FV(Kv3).Lov.Val , KEY_FV(Kv).Lov.Val , FLen + 1);
281 |
282 | KEY_FV(Kv3).Lov.Sel = KEY_FV(Kv).Lov.Sel;
283 |
284 | KEY_PV(Kv3).Lov.Val = Tmp2;
285 | Kv3->Size = Tmp3;
286 |
287 | }
288 | else
289 | {
290 | Kv3 = PiAllocateKeyValStr1( PLen + 1 );
291 | Tmp2 = KEY_PV(Kv3).Lov.Val;
292 | Tmp3 = Kv3->Size;
293 |
294 | RtlCopyMemory ( Kv3 , Kv , sizeof (KEY_VALUE) );
295 |
296 | KEY_PV(Kv3).Lov.Val = Tmp2;
297 | Kv3->Size = Tmp3;
298 | }
299 |
300 | RtlCopyMemory ( KEY_PV(Kv3).Lov.Val , KEY_FV(KeyVal).Lov.Val , PLen + 1);
301 |
302 | PROT_Debug (("Lov 0x%X->0x%X\n" , KEY_FV(Kv).Lov.Val , KEY_PV(Kv).Lov.Val));
303 | }
304 | }
305 |
306 | PiUpdateKeyNegoState ( Key , ConInfo , Answers );
307 |
308 | }
309 |
310 | VOID PiAuthMethodHandler (
311 | PKEY_VALUE KeyVal , PuCONINFO ConInfo , PLIST_ENTRY Questions , PLIST_ENTRY Answers )
312 | {
313 | KEY_NAME Key;
314 |
315 | Key = KeyVal->Key.D;
316 |
317 | //DbgPrint("%s\n" , __FUNCTION__);
318 | // TODO : Dispatch to different AuthMethod handler
319 | if (KeyVal->Flags & KEY_None )
320 | {
321 | KV(ConInfo , Key)->Flags |= KEY_None;
322 | PiUpdateKeyNegoState ( Key , ConInfo , Answers );
323 | }
324 | }
325 |
--------------------------------------------------------------------------------
/uSCSIPort/Login.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | VOID PiProcessKey( PPDU Pdu , PuCONINFO ConInfo , BOOLEAN AllocatePDU , UCHAR Opcode );
5 |
6 | PVOID PiFormatKeyValues(PLIST_ENTRY KeyVals , PULONG DataLen);
7 |
8 | PPDU PiAllocateTxtPDU ( PuCONINFO ConInfo , PPDU Pdu , PUCHAR Data , ULONG Len , UCHAR Opcode);
9 |
10 | VOID PiSetKeyState ( KEY_NAME Key , PuCONINFO ConInfo , UCHAR State);
11 |
12 | VOID PiProtError (PuCONINFO ConInfo , PUCHAR Func );
13 |
14 | VOID PiCommitPending( PuCONINFO ConInfo );
15 |
16 | VOID PiCalcNextStage(PuCONINFO ConInfo);
17 |
18 | //
19 | //Forward declaration
20 | //
21 |
22 | VOID PiAnswerPdu( PPDU Pdu , PuCONINFO ConInfo , UCHAR Opcode );
23 |
24 | BOOLEAN PiCanLoginTransit (PuCONINFO ConInfo );
25 |
26 | PPDU PiCollectStgParms(PuCONINFO ConInfo , BOOLEAN Answer);
27 |
28 | VOID PiLoginComplete( PuCONINFO ConInfo );
29 |
30 | #define PiAnswerLoginPdu( Pdu , ConInfo) \
31 | PiAnswerPdu ( Pdu , ConInfo , OP_LOGIN_REQ)
32 |
33 | #define PiLoginProcessKey(Pdu , ConInfo , AllocatePDU ) \
34 | PiProcessKey (Pdu , ConInfo , AllocatePDU , OP_LOGIN_REQ)
35 |
36 | //
37 | //
38 | //
39 | VOID PtProcessLogin( PPDU Pdu , PuCONINFO ConInfo)
40 | {
41 | PPDU NewPdu , CPdu , LPdu;
42 | PLIST_ENTRY PduEnt , PduEnt2;
43 | ULONG DataSegLen;
44 |
45 | DataSegLen = (Pdu->Bhs->GENERICBHS.DataSegmentLength[0] << 16 ) |
46 | (Pdu->Bhs->GENERICBHS.DataSegmentLength[1] << 8 ) |
47 | (Pdu->Bhs->GENERICBHS.DataSegmentLength[2] );
48 |
49 | DbgPrint(
50 | "%s Pdu=0x%p VersionMax=0x%X VersionActive=0x%X CSG=0x%X NSG=0x%X C=0x%X T=0x%X DataSegLen=0x%X\n" ,
51 | __FUNCTION__ ,
52 | Pdu ,
53 | Pdu->Bhs->LOGIN_RESPONSE.VersionMax,
54 | Pdu->Bhs->LOGIN_RESPONSE.VersionActive,
55 | Pdu->Bhs->LOGIN_RESPONSE.CSG,
56 | Pdu->Bhs->LOGIN_RESPONSE.NSG,
57 | Pdu->Bhs->LOGIN_RESPONSE.Continue,
58 | Pdu->Bhs->LOGIN_RESPONSE.Transit,
59 | DataSegLen);
60 | //
61 | // There are some errors
62 | //
63 | if ( Pdu->Bhs->LOGIN_RESPONSE.StatusClass )
64 | {
65 | /*DbgPrint("%s Status=0x%X%X\n",
66 | __FUNCTION__ ,Pdu->Bhs->LOGIN_RESPONSE.StatusClass,Pdu->Bhs->LOGIN_RESPONSE.StatusDetail);
67 | */
68 | ConInfo->LoginState = LOGIN_STAT_IDLE;
69 | goto Error;
70 | }
71 | //
72 | // Continue sending Initiator Logical PDU if any
73 | //
74 | if ( ConInfo->Answer )
75 | {
76 | #ifdef STRICT_PROT_CHECK
77 | if ( DataSegLen )
78 | PiProtError ( ConInfo , __FUNCTION__ ); // This must be a SYNC Pdu
79 | #endif
80 | goto Answer;
81 | }
82 | //
83 | // Part of Target Logical PDU
84 | //
85 | /*An initiator receiving a Text or Login
86 | Response with the C bit set to 1 MUST answer with a Text or Login
87 | Request with no data segment (DataSegmentLength 0).*/
88 | if ( Pdu->Bhs->LOGIN_RESPONSE.Continue )
89 | {
90 | #ifdef STRICT_PROT_CHECK
91 | if ( Pdu->Bhs->LOGIN_RESPONSE.Transit )
92 | PiProtError( ConInfo , __FUNCTION__ );
93 | #endif
94 | if ( !ConInfo->Logical )
95 | // Head
96 | ConInfo->Logical = Pdu;
97 | else
98 | // Part of
99 | InsertTailList ( &ConInfo->Logical->Continue, &Pdu->Continue );
100 | goto Answer;
101 | }
102 | // Logical PDU completed
103 | else if ( ConInfo->Logical )
104 | {
105 | LPdu = ConInfo->Logical;
106 | ConInfo->Logical = NULL;
107 | }
108 | else
109 | LPdu = Pdu;
110 | //
111 | // Process Target Logical PDU
112 | //
113 | PiLoginProcessKey ( LPdu ,
114 | ConInfo ,
115 | /*A Login Response with a T bit set to 1 MUST NOT contain key=value
116 | pairs that may require additional answers from the initiator within
117 | the same stage*/
118 | !Pdu->Bhs->LOGIN_RESPONSE.Transit );
119 | #ifdef STRICT_PROT_CHECK
120 | if (ConInfo->LoginState == LOGIN_STAT_STARTED &&
121 | Pdu->Bhs->LOGIN_RESPONSE.Transit )
122 | {
123 | PiProtError( ConInfo , __FUNCTION__ );
124 | }
125 | else if
126 | #else
127 | if
128 | #endif
129 | (ConInfo->LoginState == LOGIN_STAT_STARTED &&
130 | !Pdu->Bhs->LOGIN_RESPONSE.Transit)
131 | {
132 | if ( PiCanLoginTransit (ConInfo) )
133 | {
134 | PiCalcNextStage( ConInfo );
135 | PiCommitPending( ConInfo );
136 | ConInfo->LoginState = LOGIN_STAT_PENDING_TRANSIT;
137 | /*DbgPrint("%s Stage Transition 0x%X -> 0x%X Proposed\n" ,
138 | __FUNCTION__ , ConInfo->CSG , ConInfo->NSG);*/
139 | }
140 | }
141 | else if ( ConInfo->LoginState == LOGIN_STAT_PENDING_TRANSIT &&
142 | Pdu->Bhs->LOGIN_RESPONSE.Transit )
143 | {
144 | if ( LOGIN_STAGE_FullFeaturePhase == Pdu->Bhs->LOGIN_RESPONSE.NSG )
145 | {
146 | // Final Login Response
147 | //DbgPrint("%s Login Successfully CID=0x%X\n" , __FUNCTION__ , ConInfo->CID);
148 |
149 | ConInfo->LoginState = LOGIN_STAT_IDLE;
150 | ConInfo->State = CON_STAT_LOGGED_IN;
151 |
152 | if ( IsLeadingCon(ConInfo) )
153 | {
154 | ConInfo->Session->State = SESSION_STAT_LOGGED_IN;
155 | REVERSE_BYTES_SHORT( &ConInfo->Session->TSIH ,
156 | &Pdu->Bhs->LOGIN_RESPONSE.TSIH);
157 | }
158 |
159 | goto LoginComplete;
160 | }
161 | /*
162 | DbgPrint("%s Stage Transition 0x%X -> 0x%X Agreed\n" ,
163 | __FUNCTION__, ConInfo->CSG , Pdu->Bhs->LOGIN_RESPONSE.NSG);*/
164 |
165 | ConInfo->CSG = Pdu->Bhs->LOGIN_RESPONSE.NSG;
166 | PiCalcNextStage(ConInfo);
167 |
168 | ConInfo->LoginState = LOGIN_STAT_STARTED;
169 | //
170 | // Prepare next stage nego parms
171 | //
172 | PiCollectStgParms ( ConInfo , TRUE);
173 | }
174 | else if ( ConInfo->LoginState == LOGIN_STAT_PENDING_TRANSIT &&
175 | !Pdu->Bhs->LOGIN_RESPONSE.Transit )
176 | {
177 | /*
178 | 5.3.3
179 | If the target responds to a Login Request that has the T bit set to 1
180 | with a Login Response that has the T bit set to 0, the initiator
181 | should keep sending the Login Request (even empty) with the T bit set
182 | to 1, while it still wants to switch stage, until it receives the
183 | Login Response that has the T bit set to 1 or it receives a key that
184 | requires it to set the T bit to 0.
185 | */
186 | //DbgPrint("%s Stage Transition Pending\n" , __FUNCTION__);
187 | }
188 | //
189 | //
190 | //
191 | Answer:
192 |
193 | PiAnswerLoginPdu ( Pdu , ConInfo );
194 | return;
195 |
196 | Error:
197 | //TODO : may need to free the remaining Initiator's Logical PDU
198 | LoginComplete:
199 |
200 | PiLoginComplete(ConInfo);
201 | return;
202 | }
203 |
204 | BOOLEAN PiInitiatorName( PUCHAR *Name);
205 |
206 | BOOLEAN PiInitiatorAlias( PUCHAR *Alias);
207 |
208 | BOOLEAN PiAuthMethod( PUCHAR *Method);
209 |
210 | VOID PiDumpKey (PKEY_VALUE KeyVal);
211 |
212 |
213 | #define SETNEGOSTATE(Key,ConInfo) \
214 | if ( (PiKeys[Key].Attrs & KEY_DECLARATIVE) ) \
215 | PiSetKeyState( Key , ConInfo , KEY_Agreed); \
216 | else \
217 | PiSetKeyState( Key , ConInfo , KEY_Proposed)
218 |
219 | /*
220 | This function will ALWAYS allocate at least 1 PDU ,
221 | even if there should be no nego parms , in which case ,
222 | the PDU function as a sync signal
223 | */
224 |
225 | PPDU PiCollectStgParms(PuCONINFO ConInfo , BOOLEAN Answer)
226 | {
227 | PPDU NewPdu = NULL;
228 | PKEY_VALUE *Parm;
229 | PUCHAR Val , DataOut;
230 | ULONG Len , DataLen;
231 | LIST_ENTRY ParmList;
232 | PLIST_ENTRY ParmEnt;
233 | BOOLEAN Dynamic;
234 |
235 | InitializeListHead ( &ParmList );
236 | //
237 | // Security Nego
238 | //
239 | if (ConInfo->CSG == LOGIN_STAGE_SecurityNegotiation )
240 | {
241 |
242 | Parm = AddrKV(ConInfo , KEY_InitiatorName);
243 | if (!*Parm)
244 | {
245 | Dynamic = PiInitiatorName(&Val);
246 | if (Dynamic)
247 | {
248 | Len = strlen (Val) + 1;
249 | *Parm = PiAllocateKeyValStr0( Len );
250 | RtlCopyMemory (KEY_IV(*Parm).String , Val , Len-1 );
251 | *(KEY_IV(*Parm).String + Len-1 ) = '\0';
252 | ExFreePoolWithTag (Val , USCSI_TAG);
253 | }
254 | else
255 | {
256 | *Parm = PiAllocateKeyValue();
257 | KEY_IV(*Parm).String = Val;
258 | }
259 |
260 | }
261 | (*Parm)->Flags = 0;
262 | (*Parm)->Key.D = KEY_InitiatorName;
263 | SETNEGOSTATE( KEY_InitiatorName , ConInfo);
264 | InsertTailList (&ParmList , &(*Parm)->Vals );
265 |
266 | Parm = AddrKV(ConInfo , KEY_SessionType);
267 | if (!*Parm)
268 | *Parm = PiAllocateKeyValue();
269 | (*Parm)->Flags = 0;
270 | (*Parm)->Key.D = KEY_SessionType;
271 | SETNEGOSTATE( KEY_SessionType , ConInfo);
272 | InsertTailList (&ParmList ,&(*Parm)->Vals );
273 |
274 | if ( ConInfo->Session->NormalSession )
275 | {
276 | KEY_IV(*Parm).String = "Normal";
277 |
278 | Parm = AddrKV(ConInfo , KEY_TargetName);
279 | if (!*Parm)
280 | *Parm = PiAllocateKeyValue();
281 | (*Parm)->Flags = 0;
282 | (*Parm)->Key.D = KEY_TargetName;
283 | SETNEGOSTATE( KEY_TargetName , ConInfo);
284 | KEY_IV(*Parm).String = ConInfo->Session->Tgt->Tgt.TargetName;
285 | InsertTailList (&ParmList ,&(*Parm)->Vals );
286 | }
287 | else
288 | KEY_IV(*Parm).String = "Discovery";
289 |
290 | Parm = AddrKV(ConInfo , KEY_InitiatorAlias);
291 | if (!*Parm)
292 | {
293 | Dynamic = PiInitiatorAlias ( &Val);
294 | if (Dynamic)
295 | {
296 | Len = strlen (Val) + 1;
297 | *Parm = PiAllocateKeyValStr0( Len );
298 | RtlCopyMemory (KEY_IV(*Parm).String , Val , Len-1 );
299 | *(KEY_IV(*Parm).String + Len-1 ) = '\0';
300 | ExFreePoolWithTag (Val , USCSI_TAG);
301 | }
302 | else
303 | {
304 | *Parm = PiAllocateKeyValue();
305 | KEY_IV(*Parm).String = Val;
306 | }
307 | }
308 | (*Parm)->Flags = 0;
309 | (*Parm)->Key.D = KEY_InitiatorAlias;
310 | SETNEGOSTATE( KEY_InitiatorAlias , ConInfo);
311 | InsertTailList (&ParmList ,&(*Parm)->Vals );
312 |
313 | Parm = AddrKV(ConInfo , KEY_AuthMethod);
314 | if (!*Parm)
315 | {
316 | Dynamic = PiAuthMethod ( &Val);
317 | if (Dynamic)
318 | {
319 | Len = strlen (Val) + 1;
320 | *Parm = PiAllocateKeyValStr0( Len );
321 | RtlCopyMemory (KEY_FV(*Parm).String , Val , Len-1 );
322 | *(KEY_FV(*Parm).String + Len-1 ) = '\0';
323 | ExFreePoolWithTag (Val , USCSI_TAG);
324 | }
325 | else
326 | {
327 | *Parm = PiAllocateKeyValue();
328 | KEY_FV(*Parm).String = Val;
329 | }
330 | }
331 | (*Parm)->Flags = 0;
332 | (*Parm)->Key.D = KEY_AuthMethod;
333 | SETNEGOSTATE( KEY_AuthMethod , ConInfo);
334 | InsertTailList (&ParmList ,&(*Parm)->Vals );
335 |
336 |
337 | }
338 | //
339 | // Operational Nego
340 | //
341 | if ( ConInfo->CSG == LOGIN_STAGE_LoginOperationalNegotiation )
342 | {
343 |
344 | Parm = AddrKV(ConInfo , KEY_MaxConnections);
345 |
346 | (*Parm)->Flags = 0;
347 | (*Parm)->Key.D = KEY_MaxConnections;
348 | SETNEGOSTATE( KEY_MaxConnections , ConInfo);
349 | InsertTailList (&ParmList ,&(*Parm)->Vals );
350 |
351 | Parm = AddrKV(ConInfo , KEY_HeaderDigest);
352 |
353 | (*Parm)->Flags = 0;
354 | (*Parm)->Key.D = KEY_HeaderDigest;
355 | SETNEGOSTATE( KEY_HeaderDigest , ConInfo);
356 | InsertTailList (&ParmList ,&(*Parm)->Vals );
357 |
358 | Parm = AddrKV(ConInfo , KEY_DataDigest);
359 |
360 | (*Parm)->Flags = 0;
361 | (*Parm)->Key.D = KEY_DataDigest;
362 | SETNEGOSTATE( KEY_DataDigest , ConInfo);
363 | InsertTailList (&ParmList ,&(*Parm)->Vals );
364 |
365 |
366 | }
367 | //
368 | // Full Feature Nego
369 | //
370 | if ( ConInfo->CSG == LOGIN_STAGE_FullFeaturePhase )
371 | {
372 |
373 | }
374 |
375 | DataOut = PiFormatKeyValues( &ParmList , &DataLen);
376 | if (!DataOut)
377 | goto Out;
378 | /*
379 | {
380 | PUCHAR Tmp = DataOut ,End = DataOut + DataLen - 1;
381 | do
382 | {
383 | DbgPrint("Parm : %s\n" ,Tmp);
384 | while( *Tmp++ != '\0');
385 | }while( Tmp < End );
386 | }*/
387 |
388 | NewPdu = PiAllocateTxtPDU ( ConInfo ,
389 | NULL ,
390 | DataOut ,
391 | DataLen ,
392 | OP_LOGIN_REQ);
393 |
394 | if ( !NewPdu )
395 | goto Out;
396 |
397 | ParmEnt = ParmList.Flink;
398 | while ( ParmEnt != &ParmList )
399 | {
400 | PKEY_VALUE Answer;
401 | Answer = CONTAINING_RECORD (ParmEnt , KEY_VALUE , Vals);
402 | KEYOUT(Answer);
403 | ParmEnt = ParmEnt->Flink;
404 | }
405 |
406 | if (Answer)
407 | ConInfo->Answer = NewPdu;
408 |
409 | return NewPdu;
410 |
411 | Out:
412 |
413 | if ( DataOut )
414 | ExFreePoolWithTag (DataOut , USCSI_TAG);
415 |
416 | return NewPdu;
417 | }
418 |
419 | //
420 |
421 | VOID PiCalcNextStage(PuCONINFO ConInfo)
422 | {
423 | if ( LOGIN_STAGE_SecurityNegotiation == ConInfo->CSG )
424 | {
425 | if (ConInfo->SkipOperationalNegotiation)
426 | ConInfo->NSG = LOGIN_STAGE_FullFeaturePhase;
427 | else
428 | ConInfo->NSG = LOGIN_STAGE_LoginOperationalNegotiation;
429 | }
430 | else if ( LOGIN_STAGE_LoginOperationalNegotiation == ConInfo->CSG )
431 | ConInfo->NSG = LOGIN_STAGE_FullFeaturePhase;
432 | }
433 | /*
434 | Logic for a login stage transition
435 | */
436 | BOOLEAN PiCanLoginTransit (PuCONINFO ConInfo )
437 | {
438 | if ( ConInfo->MoreWorks )
439 | {
440 | ConInfo->MoreWorks = FALSE;
441 | return FALSE;
442 | }
443 |
444 | return TRUE;
445 | }
446 |
447 |
448 | VOID PiLoginComplete( PuCONINFO ConInfo )
449 | {
450 | KeSetEvent ( &ConInfo->LoginEvent , IO_NO_INCREMENT , FALSE );
451 | }
452 |
453 | PPDU PiAllocateCmdPDU (
454 | PuCONINFO ConInfo , PUCHAR DataBuf , ULONG DataSize , ULONG ReadSize , UCHAR Direction);
455 |
456 | //
457 | //
458 | //
459 |
460 | NTSTATUS PtLogin( PuCONINFO ConInfo )
461 | {
462 | PPDU Login , CPdu;
463 | PLIST_ENTRY PduEnt , PduEnt2;
464 | BOOLEAN LeadingCon;
465 |
466 | ConInfo->State = CON_STAT_IN_LOGIN;
467 |
468 | ConInfo->CSG = ConInfo->SSG;
469 | ConInfo->LoginState = LOGIN_STAT_STARTED;
470 | ConInfo->SkipOperationalNegotiation = 1;
471 |
472 | Login = PiCollectStgParms (ConInfo , FALSE);
473 |
474 | PduEnt2 = PduEnt = &Login->Continue;
475 | LeadingCon = IsLeadingCon( ConInfo );
476 |
477 | do
478 | {
479 | CPdu = CONTAINING_RECORD (PduEnt2 , PDU , Continue);
480 |
481 | REVERSE_BYTES_SHORT (&CPdu->Bhs->LOGIN_REQUEST.CID , &ConInfo->CID);
482 |
483 | if ( !LeadingCon )
484 | REVERSE_BYTES_SHORT ( &CPdu->Bhs->LOGIN_REQUEST.TSIH ,
485 | &ConInfo->Session->TSIH);
486 |
487 | CPdu->Bhs->LOGIN_REQUEST.CSG = ConInfo->CSG;
488 | CPdu->Bhs->LOGIN_REQUEST.ISID.Type = 0x00;
489 | CPdu->Bhs->LOGIN_REQUEST.ISID.B[0]=0x12;
490 | CPdu->Bhs->LOGIN_REQUEST.ISID.B[1]=0x34;
491 |
492 | PduEnt2 = PduEnt2->Flink;
493 |
494 | } while ( PduEnt2 != PduEnt );
495 |
496 | TpQueueOutPDU ( ConInfo->ConCtx , Login);
497 |
498 | KeWaitForSingleObject ( &ConInfo->LoginEvent , Executive , KernelMode , FALSE , NULL );
499 |
500 | // Test
501 | //PtNopOut( ConInfo , TRUE );
502 |
503 | if ( CON_STAT_LOGGED_IN == ConInfo->State )
504 | return STATUS_SUCCESS;
505 | else
506 | return STATUS_UNSUCCESSFUL;
507 | }
--------------------------------------------------------------------------------
/uSCSIPort/Nop.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | PPDU PiFindPendingTask(ULONG TaskTag , PuCONINFO ConInfo , BOOLEAN Remove );
5 |
6 | /*
7 | Parms
8 | TPing : Target Nopin PDU if not NULL
9 | Echo : TRUE Target Nopin expected
10 | FALSE Target Nopin not expected
11 | Immediate : Relevant only when Echo == TRUE
12 |
13 | Return
14 | Nopout PDU
15 | NULL if failed
16 | */
17 |
18 | PPDU PiAllocateNopOut(PuCONINFO ConInfo , PPDU TPing , BOOLEAN Echo, BOOLEAN Immediate)
19 | {
20 | PPDU Pdu;
21 | PSESSION Session;
22 | PuCON_CTX Ctx;
23 | FOUR_BYTE F;
24 |
25 | Session = ConInfo->Session;
26 | Ctx = ConInfo->ConCtx;
27 | F.AsULong = 0xFFFFFFFF;
28 |
29 | if ( TPing )
30 | {
31 | // Reuse the Nopin PDU
32 | Pdu = TPing;
33 | Pdu->Bhs->NOP_OUT.Opcode = OP_NOP_OUT;
34 | RtlZeroMemory ( &Pdu->Bhs->NOP_OUT.Reserved5 , 16 );
35 | }
36 | else
37 | {
38 | Pdu = TpAllocatePDU ( Ctx , OP_NOP_OUT , 0 , 0x400 );
39 | if ( !Pdu )
40 | goto Out;
41 |
42 | REVERSE_BYTES ( &Pdu->Bhs->NOP_OUT.TargetTransferTag , &F);
43 | }
44 | /*
45 | The NOP-Out MUST have the Initiator Task Tag set to a valid value
46 | only if a response in the form of NOP-In is requested
47 | */
48 | if ( Echo )
49 | {
50 | // Echo Expected
51 | // 1. This is an Initiator Ping requiring Echo
52 | // 2. This is an Initaitor Echo requiring Echo
53 | Session->TaskTag++;
54 | REVERSE_BYTES ( &Pdu->Bhs->NOP_OUT.InitiatorTaskTag , &Session->TaskTag );
55 | Pdu->Bhs->NOP_OUT.Immediate = Immediate;
56 | }
57 | else
58 | {
59 | // No Echo expected
60 | // 1. This is an a State Sync
61 | // 2. This is an Initaitor Echo requiring no Echo
62 | REVERSE_BYTES ( &Pdu->Bhs->NOP_OUT.InitiatorTaskTag , &F);
63 | /*
64 | If the Initiator Task Tag contains 0xffffffff, the I bit MUST be set
65 | to 1 ...
66 | */
67 | Pdu->Bhs->NOP_OUT.Immediate = 1;
68 | }
69 |
70 | Pdu->Bhs->NOP_OUT.Final = 1;
71 |
72 | Out:
73 |
74 | return Pdu;
75 | }
76 |
77 | /*
78 | Parms
79 | Pdu : Nopin
80 | */
81 |
82 | VOID PtProcessNopIn ( PPDU Pdu, PuCONINFO ConInfo)
83 | {
84 | PPDU NopOut;
85 | PuCON_CTX Ctx;
86 | FOUR_BYTE F , TTT , ITT;
87 | LARGE_INTEGER Time;
88 | ULONG Tmp;
89 | EIGHT_BYTE Tmp2 , Tmp3 , Tmp4;
90 |
91 | Ctx = ConInfo->ConCtx;
92 |
93 | F.AsULong = 0xFFFFFFFF;
94 | REVERSE_BYTES ( &TTT , &Pdu->Bhs->NOP_IN.TargetTransferTag);
95 |
96 | //DbgPrint("%s ConInfo=0x%p Pdu=0x%p TTT=0x%X\n" ,__FUNCTION__ , ConInfo , Pdu ,TTT.AsULong);
97 | // Target Echo
98 | if ( TTT.AsULong == F.AsULong )
99 | {
100 | KeQueryTickCount ( &Time );
101 |
102 | REVERSE_BYTES ( &ITT , &Pdu->Bhs->NOP_IN.InitiatorTaskTag);
103 | NopOut = PiFindPendingTask ( ITT.AsULong , ConInfo , TRUE);
104 | if ( NULL == NopOut )
105 | {
106 | DbgPrint("No Matching NopOut for Pdu=0x%x ITT=0x%x\n" , Pdu , ITT.AsULong);
107 | goto Out;
108 | }
109 |
110 | // Caculate Time Span
111 |
112 | REVERSE_BYTES_QUAD ( &Tmp4 , &Time);
113 | REVERSE_BYTES_QUAD ( &Tmp2 , &Tmp4);
114 | REVERSE_BYTES_QUAD ( &Tmp4 , &NopOut->SendingTime);
115 | REVERSE_BYTES_QUAD ( &Tmp3 , &Tmp4);
116 |
117 | Tmp = (ULONG)(Tmp2.AsULongLong - Tmp3.AsULongLong) * ConInfo->Session->Ns100Unit / 10;
118 |
119 | // Update Connection Statistics
120 |
121 | if ( ConInfo->Stats[CON_STATS_MIN] )
122 | ConInfo->Stats[CON_STATS_MIN] = min ( ConInfo->Stats[CON_STATS_MIN] , Tmp );
123 | else
124 | ConInfo->Stats[CON_STATS_MIN] = Tmp;
125 |
126 | ConInfo->Stats[CON_STATS_AVG] = (ConInfo->Stats[CON_STATS_AVG] + Tmp ) >> 1;
127 |
128 | if (ConInfo->Stats[CON_STATS_MAX])
129 | ConInfo->Stats[CON_STATS_MAX] = max (ConInfo->Stats[CON_STATS_MAX] , Tmp);
130 | else
131 | ConInfo->Stats[CON_STATS_MAX] = Tmp;
132 | /*
133 | DbgPrint("%s Traffics ( Min %d Max %d Avg %d) ms\n" ,
134 | __FUNCTION__ ,
135 | ConInfo->Stats[CON_STATS_MIN],
136 | ConInfo->Stats[CON_STATS_MAX],
137 | ConInfo->Stats[CON_STATS_AVG]);*/
138 |
139 | TpQueuePduRelease( Ctx , NopOut );
140 |
141 | // Test
142 | NopOut = PiAllocateNopOut ( ConInfo , NULL , TRUE , FALSE);
143 | if ( !NopOut )
144 | goto Out;
145 |
146 | TpQueueOutPDU ( Ctx , NopOut );
147 | }
148 | //Target Ping Requiring Nopout
149 | else
150 | {
151 | /*
152 | Upon receipt of a NOP-In with the Target Transfer Tag set to a valid
153 | value (not the reserved 0xffffffff), the initiator MUST respond with
154 | a NOP-Out.
155 | */
156 | NopOut = PiAllocateNopOut ( ConInfo , Pdu , FALSE , FALSE);
157 | if ( !NopOut )
158 | goto Out;
159 |
160 | TpQueueOutPDU ( Ctx , NopOut );
161 | }
162 |
163 | Out:
164 |
165 | TpQueuePduRelease( Ctx , Pdu );
166 | return;
167 | }
168 |
169 | /*
170 | Parms
171 | Echo : Does this Nop-Out expect a Nop-In ?
172 | */
173 | VOID PtNopOut (PuCONINFO ConInfo , BOOLEAN Echo)
174 | {
175 | PPDU Pdu;
176 |
177 | Pdu = PiAllocateNopOut ( ConInfo , NULL , TRUE , TRUE);
178 |
179 | if ( Pdu )
180 | TpQueueOutPDU ( ConInfo->ConCtx , Pdu );
181 | }
--------------------------------------------------------------------------------
/uSCSIPort/ProtUtils.c:
--------------------------------------------------------------------------------
1 | #include "precomp.h"
2 |
3 | PKEY_VALUE PiFormatKeyValue (PKEY_VALUE Val);
4 |
5 | ULONG PiGetKeyState (KEY_NAME Key , PuCONINFO ConInfo );
6 |
7 | VOID PiSetKeyState ( KEY_NAME Key , PuCONINFO ConInfo , UCHAR State);
8 |
9 | BOOLEAN PiInitiatorName( PUCHAR *Name)
10 | {
11 | *Name = "iqn.2009-09.yushang.com.uSCSI:vDisk.0001";
12 | return FALSE;
13 | }
14 |
15 | BOOLEAN PiInitiatorAlias( PUCHAR *Alias)
16 | {
17 | *Alias = "Personal Disk of yushang";
18 | return FALSE;
19 | }
20 |
21 | BOOLEAN PiAuthMethod( PUCHAR *Method)
22 | {
23 | *Method = "CHAP,KRB5,SPKM1,SPKM2,SRP,None";
24 | return FALSE;
25 | }
26 |
27 | VOID PiProtError (PuCONINFO ConInfo , PUCHAR Func )
28 | {
29 | PROT_Debug (("%s\n" , Func ));
30 | //TODO: Colse connection
31 | }
32 |
33 | /*
34 | Memory Layout
35 |
36 | -------- <- KEY_VALUE
37 | ...
38 | -------- <- Value[0].String if any
39 | ...
40 | -------- <- Value[1].String if any
41 | ...
42 | -------- <- FormatStr if any
43 | ...
44 | --------
45 | */
46 | PKEY_VALUE PiAllocateKeyVal(ULONG StrLen , ULONG StrLen2 , ULONG StrLen3)
47 | {
48 | PKEY_VALUE Kv;
49 |
50 | Kv = ExAllocatePoolWithTag ( PagedPool ,
51 | sizeof (KEY_VALUE) + StrLen + StrLen2 + StrLen3,
52 | USCSI_TAG);
53 | if ( !Kv )
54 | return Kv;
55 |
56 | InitializeListHead (&Kv->Vals);
57 | Kv->Size = sizeof (KEY_VALUE) + StrLen + StrLen2 + StrLen3;
58 | Kv->Len = 0;
59 | Kv->Flags = 0;
60 | Kv->NegoRetries = 0;
61 | Kv->Formal = KEY_F;
62 | Kv->Pending = KEY_P;
63 |
64 | if ( StrLen )
65 | Kv->Value[0].String = (PUCHAR)(Kv+1);
66 | else
67 | Kv->Value[0].String = NULL;
68 |
69 | if (StrLen2)
70 | Kv->Value[1].String = (PUCHAR)(Kv+1) + StrLen;
71 | else
72 | Kv->Value[1].String = NULL;
73 |
74 | if (StrLen3)
75 | Kv->FormatStr = (PUCHAR)(Kv+1) + StrLen + StrLen2;
76 | else
77 | Kv->FormatStr = NULL;
78 |
79 | return Kv;
80 | }
81 |
82 | /*
83 | Called every turn of PiProcessKeys
84 | */
85 | VOID PiCheckNegoState( PuCONINFO ConInfo , PLIST_ENTRY Answers )
86 | {
87 | ULONG KeyState;
88 | PKEY_VALUE Kv , Kv2;
89 | KEY_NAME Key;
90 |
91 | for ( Key = 0 ; Key < KEY_LastKey ; Key++)
92 | {
93 | if ( Key == KEY_MaxSessionKey )
94 | continue;
95 |
96 | Kv = KV( ConInfo , Key );
97 |
98 | // Some Key may not get initialized
99 |
100 | if (!Kv)
101 | continue;
102 |
103 | if ( KEY_Proposed == PiGetKeyState ( Key , ConInfo) )
104 | {
105 | Kv->NegoRetries++;
106 |
107 | if ( Kv->NegoRetries <= PiKeys[Key].NegoRetries )
108 | {
109 | // Repropose it
110 | Kv2 = PiFormatKeyValue ( Kv );
111 | InsertTailList ( Answers , &Kv2->Vals );
112 | ConInfo->MoreWorks = TRUE;
113 | }
114 | else if ( PiKeys[Key].NegoFailAction == KEY_NEGO_FAIL_INGORE )
115 | {
116 | PiSetKeyState ( Key , ConInfo , KEY_Agreed );
117 | }
118 | else if ( PiKeys[Key].NegoFailAction == KEY_NEGO_FAIL_CLOSE )
119 | {
120 | // Close XPT
121 | PROT_Debug(("Close Connection\n"));
122 | }
123 | }
124 | }
125 | }
126 |
127 | //
128 | // Allocate a PDU for LOGIN or TEXT
129 | // Segmentation if needed
130 | //
131 |
132 | PPDU PiAllocateTxtPDU(PuCONINFO ConInfo , PPDU Pdu , PUCHAR Data , ULONG Len , UCHAR Opcode)
133 | {
134 | LONG Remaining , DataLen , MaxDataSeg;
135 | PPDU NewPdu , Tmp;
136 | PUCHAR Data2;
137 |
138 | Data2 = Data;
139 | NewPdu = NULL;
140 | Remaining = Len;
141 |
142 | /*5.3
143 | The default MaxRecvDataSegmentLength is used during Login
144 | */
145 | MaxDataSeg = (LONG)KEY_FV(KV(ConInfo,KEY_MaxRecvDataSegmentLength)).Number;
146 |
147 | do
148 | {
149 | DataLen = min ( Remaining , MaxDataSeg );
150 |
151 | Tmp = TpAllocatePDU( ConInfo->ConCtx , Opcode , 0 , 0 );
152 |
153 | if ( !Tmp )
154 | goto ErrorOut;
155 | else if ( NewPdu )
156 | InsertTailList ( &NewPdu->Continue , &Tmp->Continue); //Part of
157 | else
158 | NewPdu = Tmp; //Head
159 |
160 | Tmp->Data = Data2;
161 |
162 | Tmp->Bhs->GENERICBHS.Immediate = 1;
163 | REVERSE_3BYTES ( &Tmp->Bhs->GENERICBHS.DataSegmentLength , &DataLen);
164 | /*
165 | Tmp->Bhs->GENERICBHS.DataSegmentLength[0] = (UCHAR)(( DataLen & 0xFF0000 ) >> 16);
166 | Tmp->Bhs->GENERICBHS.DataSegmentLength[1] = (UCHAR)(( DataLen & 0xFF00 ) >> 8);
167 | Tmp->Bhs->GENERICBHS.DataSegmentLength[2] = (UCHAR)( DataLen & 0xFF );*/
168 |
169 | if ( Opcode == OP_LOGIN_REQ)
170 | Tmp->Bhs->LOGIN_REQUEST.Continue = 1;
171 | else if ( Opcode == OP_TXT_REQ )
172 | Tmp->Bhs->TXT_REQUEST.Continue = 1;
173 |
174 | //???
175 | if (Pdu)
176 | RtlCopyMemory ( Tmp->Bhs->TXT_REQUEST.TargetTransferTag,
177 | Pdu->Bhs->TXT_RESPONSE.TargetTransferTag,
178 | 4);
179 | Data2 += DataLen;
180 |
181 | Remaining -= DataLen;
182 |
183 | }while ( Remaining > 0 );
184 | //
185 | // Set last one's Buffer so we can release it later
186 | //
187 | Tmp->Buffer = Data;
188 | //
189 | // and Continue bit
190 | //
191 | if ( Opcode == OP_LOGIN_REQ)
192 | Tmp->Bhs->LOGIN_REQUEST.Continue = 0;
193 | else if ( Opcode == OP_TXT_REQ )
194 | Tmp->Bhs->TXT_REQUEST.Continue = 0;
195 |
196 | return NewPdu;
197 |
198 | ErrorOut:
199 |
200 | if (NewPdu)
201 | {
202 | TpQueuePduRelease ( ConInfo->ConCtx , NewPdu );
203 | /*
204 | while ( !IsListEmpty ( &NewPdu->Continue) )
205 | {
206 | PPDU Tmp;
207 | PLIST_ENTRY Ent;
208 | Ent = RemoveHeadList ( &NewPdu->Continue );
209 | Tmp = CONTAINING_RECORD ( Ent , PDU , Continue );
210 | ExFreePoolWithTag( Tmp , USCSI_TAG );
211 | }
212 | ExFreePoolWithTag( NewPdu , USCSI_TAG );*/
213 | }
214 |
215 | return NULL;
216 | }
217 |
218 | /*
219 | Called for normal LOGIN or TEXT response PDU
220 | */
221 | VOID PiAnswerPdu( PPDU Pdu , PuCONINFO ConInfo , UCHAR Opcode )
222 | {
223 | LONG DataLen;
224 | PPDU LPdu , LPdu2;
225 | PLIST_ENTRY PduEnt;
226 |
227 | LPdu = ConInfo->Answer;
228 |
229 | if ( !LPdu )
230 | //Allocate a PDU with DataSegmentLength = 0 , the so-called SYNC PDU
231 | LPdu = TpAllocatePDU( ConInfo->ConCtx , Opcode , 0 , 0 );
232 |
233 | if ( !IsListEmpty ( &LPdu->Continue) )
234 | {
235 | // Part of a logical PDU
236 | LPdu2 = CONTAINING_RECORD ( LPdu->Continue.Flink , PDU , Continue );
237 | ConInfo->Answer = LPdu2;
238 | InitializeListHead ( &LPdu->Continue );
239 |
240 | if ( Opcode == OP_LOGIN_REQ )
241 | LPdu->Bhs->LOGIN_REQUEST.Continue = 1;
242 | else if ( Opcode == OP_TXT_REQ)
243 | LPdu->Bhs->TXT_REQUEST.Continue = 1;
244 | }
245 | else
246 | {
247 | // End of a logical PDU
248 | ConInfo->Answer = NULL;
249 |
250 | if ( Opcode == OP_LOGIN_REQ && ConInfo->LoginState == LOGIN_STAT_PENDING_TRANSIT )
251 | LPdu->Bhs->LOGIN_REQUEST.Transit = 1;
252 |
253 | else if ( Opcode == OP_TXT_REQ && ConInfo->TextState == TXT_STAT_PENDING_COMPLETE)
254 | LPdu->Bhs->TXT_REQUEST.Final = 1;
255 | }
256 |
257 | if ( Opcode == OP_LOGIN_REQ )
258 | {
259 | LPdu->Bhs->LOGIN_REQUEST.CSG = ConInfo->CSG;
260 | /*
261 | 10.12.3
262 | The next stage value is only valid when the T bit is 1; otherwise, it is reserved
263 | */
264 | if ( LPdu->Bhs->LOGIN_REQUEST.Transit )
265 | LPdu->Bhs->LOGIN_REQUEST.NSG = ConInfo->NSG;
266 |
267 | REVERSE_BYTES_SHORT ( &LPdu->Bhs->LOGIN_REQUEST.CID , &ConInfo->CID);
268 | if (!IsLeadingCon(ConInfo))
269 | REVERSE_BYTES_SHORT ( &LPdu->Bhs->LOGIN_REQUEST.TSIH , &ConInfo->Session->TSIH);
270 | }
271 | /*
272 | DbgPrint("%s LPdu=0x%X CSG=0x%X NSG=0x%X C=0x%X T=0x%X\n" ,
273 | __FUNCTION__ , LPdu ,LPdu->Bhs->LOGIN_REQUEST.CSG,LPdu->Bhs->LOGIN_REQUEST.NSG,
274 | LPdu->Bhs->LOGIN_REQUEST.Continue,LPdu->Bhs->LOGIN_REQUEST.Transit);*/
275 |
276 | TpQueueOutPDU( ConInfo->ConCtx , LPdu );
277 | }
278 |
279 | //
280 | // TODO Called at the end of a successful nego
281 | //
282 |
283 | VOID PiCommitPending( PuCONINFO ConInfo )
284 | {
285 | KEY_NAME Key;
286 | UCHAR Tmp;
287 | PKEY_VALUE Kv;
288 |
289 | /*
290 | for ( Key = 0 ; Key < KEY_LastKey ; Key++)
291 | {
292 | Kv = KV( ConInfo , Key );
293 |
294 | if (!Kv)
295 | continue;
296 |
297 | if (PiIsKeyDeclarative (Key))
298 | continue;
299 |
300 | Tmp = Kv->Formal;
301 | Kv->Formal = Kv->Pending;
302 | Kv->Pending = Tmp;
303 | }*/
304 | }
305 |
306 | //
307 | //
308 | //
309 |
310 | __inline ULONG PiHashTaskTag(ULONG Task)
311 | {
312 | return (Task % PENDING_TASK_HASH_SIZE);
313 | }
314 |
315 | //
316 | //
317 | //
318 |
319 | VOID PiQueuePendingTask(PuCONINFO ConInfo , PPDU Pdu)
320 | {
321 | ULONG Slot;
322 | FOUR_BYTE ITT;
323 |
324 | REVERSE_BYTES ( &ITT , &Pdu->Bhs->GENERICBHS.InitiatorTaskTag );
325 | Slot = PiHashTaskTag ( ITT.AsULong );
326 | InsertTailList ( &ConInfo->PendingTasks[Slot] , &Pdu->PDUList );
327 | }
328 |
329 | //
330 | //
331 | //
332 |
333 | VOID PiDequeuePendingTask(PuCONINFO ConInfo , PPDU Pdu)
334 | {
335 | KIRQL OldIrql;
336 |
337 | KeAcquireSpinLock( &ConInfo->PendingTasksLock , &OldIrql);
338 | RemoveHeadList ( Pdu->PDUList.Blink );
339 | InitializeListHead ( &Pdu->PDUList );
340 | KeReleaseSpinLock( &ConInfo->PendingTasksLock , OldIrql);
341 | }
342 |
343 | //
344 | //
345 | //
346 |
347 | PPDU PiFindPendingTask(ULONG TaskTag , PuCONINFO ConInfo , BOOLEAN Remove)
348 | {
349 | FOUR_BYTE ITT;
350 | PLIST_ENTRY Entry , Tmp;
351 | PPDU Pdu;
352 | KIRQL OldIrql;
353 |
354 | KeAcquireSpinLock( &ConInfo->PendingTasksLock , &OldIrql);
355 |
356 | Entry = &ConInfo->PendingTasks[ PiHashTaskTag(TaskTag) ];
357 |
358 | Tmp = Entry->Flink;
359 |
360 | while ( Tmp != Entry )
361 | {
362 | Pdu = CONTAINING_RECORD (Tmp , PDU , PDUList );
363 |
364 | REVERSE_BYTES ( &ITT , &Pdu->Bhs->GENERICBHS.InitiatorTaskTag);
365 | if (ITT.AsULong == TaskTag )
366 | {
367 | if (Remove)
368 | {
369 | RemoveHeadList ( Pdu->PDUList.Blink );
370 | InitializeListHead ( &Pdu->PDUList );
371 | }
372 | KeReleaseSpinLock( &ConInfo->PendingTasksLock , OldIrql);
373 | return Pdu;
374 | }
375 |
376 | Tmp = Tmp->Flink;
377 | }
378 | KeReleaseSpinLock( &ConInfo->PendingTasksLock , OldIrql);
379 | return NULL;
380 | }
381 |
382 | //
383 | // Called by TDI when PDU sending complete
384 | // This function may run at DISPATCH_LEVEL
385 | //
386 |
387 | NTSTATUS PiCompletePDU (PDEVICE_OBJECT DevObj , PIRP Irp , PVOID Ctx)
388 | {
389 | PuCONINFO ConInfo;
390 | PPDU Pdu;
391 | FOUR_BYTE ExpectedDataTansferLength , DataSegmentLength , ITT;
392 | UCHAR Opcode;
393 |
394 | Pdu = (PPDU)Ctx;
395 |
396 | ConInfo = Pdu->ConCtx->ConInfo;
397 | Opcode = Pdu->Bhs->GENERICBHS.Opcode;
398 |
399 | KeQueryTickCount ( &Pdu->SendingTime);
400 |
401 | if ( Irp->PendingReturned )
402 | IoMarkIrpPending( Irp );
403 |
404 | if ( Opcode == OP_DATA_OUT)
405 | goto Out;
406 |
407 | if (Opcode == OP_SCSI_CMD ||
408 | Opcode == OP_SCSI_TASK_REQ ||
409 | Opcode == OP_SNACK_REQ )
410 | goto Queue;
411 |
412 | if ( Opcode == OP_NOP_OUT)
413 | {
414 | REVERSE_BYTES ( &ITT , &Pdu->Bhs->NOP_OUT.InitiatorTaskTag );
415 |
416 | if ( ITT.AsULong != 0xFFFFFFFF )
417 | // Echo Expected
418 | // Queue it in Pending Task Queue
419 | goto Queue;
420 |
421 | // Just Release it
422 | goto Release;
423 | }
424 |
425 | if ( Opcode == OP_LOGIN_REQ ||
426 | Opcode == OP_LOGOUT_REQ ||
427 | Opcode == OP_TXT_REQ)
428 | goto Release;
429 |
430 | Out:
431 | return STATUS_SUCCESS;
432 |
433 | Release:
434 |
435 | TpQueuePduRelease( Pdu->ConCtx , Pdu );
436 | return STATUS_SUCCESS;
437 |
438 | Queue:
439 |
440 | PiQueuePendingTask ( ConInfo , Pdu );
441 | return STATUS_SUCCESS;
442 | }
443 |
444 | //
445 | // Release PDU at PASSIVE_LEVEL
446 | //
447 |
448 | VOID PiPduReleaser(IN PVOID Parameter)
449 | {
450 | NTSTATUS Status;
451 | PLIST_ENTRY PduEnt;
452 | PPDU Pdu;
453 | PSESSION Session = (PSESSION)Parameter;
454 |
455 | while (TRUE)
456 | {
457 | Status =
458 | KeWaitForSingleObject(&Session->PduReleaseEvent, Executive, KernelMode, FALSE, NULL );
459 | KeClearEvent( &Session->PduReleaseEvent );
460 |
461 | while ( PduEnt =
462 | ExInterlockedRemoveHeadList ( &Session->PduRelease , &Session->PduReleaseLock ) )
463 | {
464 | Pdu = CONTAINING_RECORD ( PduEnt , PDU , PDUList );
465 | InitializeListHead ( &Pdu->PDUList);
466 | TpFreePDU( Pdu->ConCtx , Pdu , 0 );
467 | }
468 | }
469 | }
470 |
--------------------------------------------------------------------------------
/uSCSIPort/Protocol.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | BOOLEAN PiInitKeys();
5 |
6 | //
7 | // Protocol Handlers
8 | //
9 |
10 | VOID PtProcessAsyncMsg ( PPDU Pdu , PuCONINFO ConInfo)
11 | {
12 | KdPrintEx((DPFLTR_USCSI,DBG_PROTOCOL,
13 | "%s ConInfo 0x%p Pdu 0x%p\n" ,
14 | __FUNCTION__ ,
15 | ConInfo ,
16 | Pdu));
17 | }
18 |
19 |
20 | VOID PtProcessLogout ( PPDU Pdu , PuCONINFO ConInfo)
21 | {
22 | KdPrintEx((DPFLTR_USCSI,DBG_PROTOCOL,
23 | "%s ConInfo 0x%p Pdu 0x%p\n" ,
24 | __FUNCTION__ ,
25 | ConInfo ,
26 | Pdu));
27 | }
28 |
29 | NTSTATUS PtInit()
30 | {
31 | if ( PiInitKeys() )
32 | return STATUS_SUCCESS;
33 |
34 | return STATUS_UNSUCCESSFUL;
35 | }
36 |
37 | NTSTATUS PtUnInit()
38 | {
39 | //TODO:
40 | return STATUS_SUCCESS;
41 | }
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/uSCSIPort/Protocol.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef _PROTOCOL_H
3 | #define _PROTOCOL_H
4 |
5 | #define BHS_SIZE 48
6 |
7 | #define OP_NOP_OUT 0x00
8 | #define OP_SCSI_CMD 0x01
9 | #define OP_SCSI_TASK_REQ 0x02
10 | #define OP_LOGIN_REQ 0x03
11 | #define OP_TXT_REQ 0x04
12 | #define OP_DATA_OUT 0x05
13 | #define OP_LOGOUT_REQ 0x06
14 | #define OP_SNACK_REQ 0x10
15 |
16 | #define OP_NOP_IN 0x20
17 | #define OP_SCSI_REP 0x21
18 | #define OP_SCSI_TASK_REP 0x22
19 | #define OP_LOGIN_REP 0x23
20 | #define OP_TXT_REP 0x24
21 | #define OP_DATA_IN 0x25
22 | #define OP_LOGOUT_REP 0x26
23 | #define OP_R2T 0x31
24 | #define OP_ASYNC_MSG 0x32
25 | #define OP_REJECT 0x3f
26 |
27 | typedef union _BHS
28 | {
29 | struct _BHS_BUF
30 | {
31 | UCHAR Buf[48];
32 | }BHS_BUF , *PBHS_BUF;
33 |
34 | struct _GENERICBHS
35 | {
36 | UCHAR Opcode:6;
37 | UCHAR Immediate:1;
38 | UCHAR Reserved1:1;
39 |
40 | UCHAR Opcode_spec:7;
41 | UCHAR Final:1;
42 |
43 | UCHAR Opcode_spec2[2];
44 | UCHAR TotalAHSLength;
45 | UCHAR DataSegmentLength[3];
46 | union
47 | {
48 | UCHAR LUN[8];
49 | UCHAR Opcode_spec3[8];
50 | };
51 | UCHAR InitiatorTaskTag[4];
52 | UCHAR Opcode_spec4[28];
53 | }GENERICBHS , *PGENERICBHS;
54 |
55 | struct _STAT_FIELDS
56 | {
57 | UCHAR Reserved1[16];
58 |
59 | UCHAR InitiatorTaskTag[4];
60 |
61 | UCHAR TargetTransferTag[4];
62 |
63 | union
64 | {
65 | // 24
66 | UCHAR CmdSN[4];
67 | UCHAR StatSN[4];
68 | };
69 | union
70 | {
71 | // 28
72 | UCHAR ExpStatSN[4];
73 | UCHAR ExpCmdSN[4];
74 | };
75 | union
76 | {
77 | // 32
78 | UCHAR Reserved2[4];
79 | UCHAR MaxCmdSN[4];
80 | };
81 | union
82 | {
83 | // 36
84 | UCHAR Reserved3[4];
85 | UCHAR DataSN[4];
86 | UCHAR R2TSN[4];
87 | UCHAR ExpDataSN[4];
88 | };
89 | }STAT_FIELDS , *PSTAT_FIELDS;
90 | //0x01
91 | struct _SCSI_CMD
92 | {
93 | UCHAR Opcode:6;
94 | UCHAR Immediate:1;
95 | UCHAR Reserved:1;
96 |
97 | UCHAR Attr:3;
98 | UCHAR Reserved2:2;
99 | UCHAR Write:1;
100 | UCHAR Read:1;
101 | UCHAR Final:1;
102 |
103 | UCHAR Reserved3[2];
104 | UCHAR TotalAHSLength;
105 | UCHAR DataSegmentLength[3];
106 |
107 | UCHAR LUN[8];
108 |
109 | UCHAR InitiatorTaskTag[4];
110 | UCHAR ExpectedDataTansferLength[4];
111 | UCHAR CmdSN[4];
112 | UCHAR ExpStatSN[4];
113 |
114 | UCHAR Cdb[16];
115 |
116 | }SCSI_CMD , *PSCSI_CMD;
117 | //0x21
118 | struct _SCSI_RESPONSE
119 | {
120 | UCHAR Opcode:6;
121 | UCHAR Reserved:2;
122 |
123 | UCHAR Reserved3:1;
124 | UCHAR U:1;
125 | UCHAR O:1;
126 | UCHAR u:1;
127 | UCHAR o:1;
128 | UCHAR Reserved2:2;
129 | UCHAR Final:1;
130 |
131 | UCHAR Response;
132 | UCHAR Status;
133 |
134 | UCHAR TotalAHSLength;
135 | UCHAR DataSegmentLength[3];
136 |
137 | UCHAR Reserved4[8];
138 |
139 | UCHAR InitiatorTaskTag[4];
140 | union
141 | {
142 | UCHAR SNACKTag[4];
143 | UCHAR Reserved5[4];
144 | };
145 | UCHAR StatSN[4];
146 | UCHAR ExpCmdSN[4];
147 | UCHAR MaxCmdSN[4];
148 | union
149 | {
150 | UCHAR ExpDataSN[4];
151 | UCHAR Reserved6[4];
152 | };
153 | union
154 | {
155 | UCHAR BiReadResidualCount[4];
156 | UCHAR Reserved7[4];
157 | };
158 | union
159 | {
160 | UCHAR ResidualCount[4];
161 | UCHAR Reserved8[4];
162 | };
163 | }SCSI_RESPONSE , *PSCSI_RESPONSE;
164 |
165 | //0x02
166 | struct _TASK_MANAGEMENT
167 | {
168 | UCHAR Opcode:6;
169 | UCHAR Immediate:1;
170 | UCHAR Reserved1:1;
171 |
172 | UCHAR Function:7;
173 | UCHAR Final:1;
174 |
175 | UCHAR Reserved2[2];
176 | UCHAR TotalAHSLength;
177 | UCHAR DataSegmentLength[3];
178 | union
179 | {
180 | UCHAR LUN[8];
181 | UCHAR Reserved3[8];
182 | };
183 | UCHAR InitiatorTaskTag[4];
184 | UCHAR RefedTaskTag[4];
185 | UCHAR CmdSN[4];
186 | UCHAR ExpStatSN[4];
187 | union
188 | {
189 | UCHAR RefCmdSN[4];
190 | UCHAR Reserved4[4];
191 | };
192 | union
193 | {
194 | UCHAR ExpDataSN[4];
195 | UCHAR Reserved5[4];
196 | };
197 | UCHAR Reserved6[28];
198 | }TASK_MANAGEMENT , *PTASK_MANAGEMENT;
199 |
200 | //0x05
201 | struct _SCSI_DATA_OUT
202 | {
203 | UCHAR Opcode:6;
204 | UCHAR Reserved1:2;
205 |
206 | UCHAR Reserved2:7;
207 | UCHAR Final:1;
208 | UCHAR Reserved3[2];
209 |
210 | UCHAR TotalAHSLength;
211 | UCHAR DataSegmentLength[3];
212 | union
213 | {
214 | UCHAR LUN[8];
215 | UCHAR Reserved4[8];
216 | };
217 | UCHAR InitiatorTaskTag[4];
218 | UCHAR TargetTansferTag[4];
219 | UCHAR Reserved5[4];
220 | UCHAR ExpStatSN[4];
221 | UCHAR Reserved6[4];
222 | UCHAR DataSN[4];
223 | UCHAR BufferOffset[4];
224 | UCHAR Reserved7[4];
225 | }SCSI_DATA_OUT , *PSCSI_DATA_OUT;
226 | //0x25
227 | struct _SCSI_DATA_IN
228 | {
229 | UCHAR Opcode:6;
230 | UCHAR Reserved1:2;
231 |
232 | UCHAR S:1;
233 | UCHAR U:1;
234 | UCHAR O:1;
235 | UCHAR Reserved2:3;
236 | UCHAR Ack:1;
237 | UCHAR Final:1;
238 |
239 | UCHAR Reserved3;
240 | union
241 | {
242 | UCHAR Status;
243 | UCHAR Reserved4;
244 | };
245 |
246 | UCHAR TotalAHSLength;
247 | UCHAR DataSegmentLength[3];
248 | union
249 | {
250 | UCHAR LUN[8];
251 | UCHAR Reserved5[8];
252 | };
253 | UCHAR InitiatorTaskTag[4];
254 | UCHAR TargetTransferTag[4];
255 | union
256 | {
257 | UCHAR StatSN[4];
258 | UCHAR Reserved6[4];
259 | };
260 | UCHAR ExpCmdSN[4];
261 | UCHAR MaxCmdSN[4];
262 | UCHAR DataSN[4];
263 | UCHAR BufferOffset[4];
264 | UCHAR ResidualCount[4];
265 | }SCSI_DATA_IN , *PSCSI_DATA_IN;
266 |
267 | //0x31
268 | struct _R2T
269 | {
270 | UCHAR Opcode:6;
271 | UCHAR Reserved1:2;
272 |
273 | UCHAR Reserved2:7;
274 | UCHAR Final:1;
275 | UCHAR Reserved3[2];
276 |
277 | UCHAR TotalAHSLength;
278 | UCHAR DataSegmentLength[3];
279 | UCHAR LUN[8];
280 |
281 | UCHAR InitiatorTaskTag[4];
282 | UCHAR TargetTansferTag[4];
283 | UCHAR StatSN[4];
284 | UCHAR ExpCmdSN[4];
285 | UCHAR MaxCmdSN[4];
286 | UCHAR R2TSN[4];
287 | UCHAR BufferOffset[4];
288 | UCHAR DesiredDataTransferLength[4];
289 | }R2T , *PR2T;
290 |
291 | //0x32
292 | struct _ASYNC_MESSAGE
293 | {
294 | UCHAR Opcode:6;
295 | UCHAR Reserved1:2;
296 |
297 | UCHAR Reserved2:7;
298 | UCHAR Final:1;
299 | UCHAR Reserved3[2];
300 |
301 | UCHAR TotalAHSLength;
302 | UCHAR DataSegmentLength[3];
303 | union
304 | {
305 | UCHAR LUN[8];
306 | UCHAR Reserved4[8];
307 | };
308 | UCHAR FFFF[4];
309 | UCHAR Reserved5[4];
310 | UCHAR StatSN[4];
311 | UCHAR ExpCmdSN[4];
312 | UCHAR MaxCmdSN[4];
313 | UCHAR AsyncEvent;
314 | UCHAR AsyncVCode;
315 | union
316 | {
317 | UCHAR Parameter1[2];
318 | UCHAR Reserved6[2];
319 | };
320 | union
321 | {
322 | UCHAR Parameter2[2];
323 | UCHAR Reserved7[2];
324 | };
325 | union
326 | {
327 | UCHAR Parameter3[2];
328 | UCHAR Reserved8[2];
329 | };
330 | UCHAR Reserved9[4];
331 | }ASYNC_MESSAGE , *PASYNC_MESSAGE;
332 |
333 | //0x04
334 | struct _TXT_REQUEST
335 | {
336 | UCHAR Opcode:6;
337 | UCHAR Immediate:1;
338 | UCHAR Reserved1:1;
339 |
340 | UCHAR Reserved2:6;
341 | UCHAR Continue:1;
342 | UCHAR Final:1;
343 |
344 | UCHAR Reserved3[2];
345 |
346 | UCHAR TotalAHSLength;
347 | UCHAR DataSegmentLength[3];
348 | union
349 | {
350 | UCHAR LUN[8];
351 | UCHAR Reserved4[8];
352 | };
353 | UCHAR InitiatorTaskTag[4];
354 | UCHAR TargetTransferTag[4];
355 | UCHAR CmdSN[4];
356 | UCHAR ExpStatSN[4];
357 | UCHAR Reserved5[16];
358 |
359 | }TXT_REQUEST,*PTXT_REQUEST;
360 |
361 | //0x24
362 | struct _TXT_RESPONSE
363 | {
364 | UCHAR Opcode:6;
365 | UCHAR Reserved1:2;
366 |
367 | UCHAR Reserved2:6;
368 | UCHAR Continue:1;
369 | UCHAR Final:1;
370 | UCHAR Reserved3[2];
371 |
372 | UCHAR TotalAHSLength;
373 | UCHAR DataSegmentLength[3];
374 | union
375 | {
376 | UCHAR LUN[8];
377 | UCHAR Reserved4[8];
378 | };
379 | UCHAR InitiatorTaskTag[4];
380 | UCHAR TargetTransferTag[4];
381 | UCHAR StatSN[4];
382 | UCHAR ExpCmdSN[4];
383 | UCHAR MaxCmdSN[4];
384 | UCHAR Reserved5[12];
385 | }TXT_RESPONSE , *PTXT_RESPONSE;
386 |
387 | //0x03
388 | struct _LOGIN_REQUEST
389 | {
390 | UCHAR Opcode:6;
391 | UCHAR Immediate:1;
392 | UCHAR Reserved1:1;
393 |
394 | UCHAR NSG:2;
395 | UCHAR CSG:2;
396 | UCHAR Reserved2:2;
397 | UCHAR Continue:1;
398 | UCHAR Transit:1;
399 |
400 | UCHAR VersionMax;
401 | UCHAR VersionMin;
402 | UCHAR TotalAHSLength;
403 | UCHAR DataSegmentLength[3];
404 | struct _ISID
405 | {
406 | UCHAR A:6;
407 | UCHAR Type:2;
408 | UCHAR B[2] , C , D[2];
409 | }ISID;
410 |
411 | UCHAR TSIH[2];
412 | UCHAR InitiatorTaskTag[4];
413 | UCHAR CID[2];
414 | UCHAR Reserved3[2];
415 | UCHAR CmdSN[4];
416 | union
417 | {
418 | UCHAR ExpStatSN[4];
419 | UCHAR Reserved4[4];
420 | };
421 | UCHAR Reserved5[16];
422 | }LOGIN_REQUEST , *PLOGIN_REQUEST;
423 |
424 | //0x23
425 | struct _LOGIN_RESPONSE
426 | {
427 | UCHAR Opcode:6;
428 | UCHAR Immediate:1;
429 | UCHAR Reserved1:1;
430 |
431 | UCHAR NSG:2;
432 | UCHAR CSG:2;
433 | UCHAR Reserved2:2;
434 | UCHAR Continue:1;
435 | UCHAR Transit:1;
436 |
437 | UCHAR VersionMax;
438 | UCHAR VersionActive;
439 | UCHAR TotalAHSLength;
440 | UCHAR DataSegmentLength[3];
441 | UCHAR ISID[6];
442 | UCHAR TSIH[2];
443 |
444 | UCHAR InitiatorTaskTag[4];
445 | UCHAR Reserved3[4];
446 | UCHAR StatSN[4];
447 | UCHAR ExpCmdSN[4];
448 | UCHAR MaxCmdSN[4];
449 |
450 | UCHAR StatusClass;
451 | UCHAR StatusDetail;
452 |
453 | UCHAR Reserved4[8];
454 |
455 | }LOGIN_RESPONSE , *PLOGIN_RESPONSE;
456 |
457 | //0x06
458 | struct _LOGOUT_REQUEST
459 | {
460 | UCHAR Opcode:6;
461 | UCHAR Immediate:1;
462 | UCHAR Reserved1:1;
463 |
464 | UCHAR ReasonCode:7;
465 | UCHAR Final:1;
466 | UCHAR Reserved2[2];
467 |
468 | UCHAR TotalAHSLength;
469 | UCHAR DataSegmentLength[3];
470 |
471 | UCHAR Reserved3[8];
472 |
473 | UCHAR InitiatorTaskTag[4];
474 | union
475 | {
476 | UCHAR CID[2];
477 | UCHAR Reserved4[2];
478 | };
479 | UCHAR Reserved5[2];
480 | UCHAR CmdSN[4];
481 | UCHAR ExpStatSN[4];
482 |
483 | UCHAR Reserved6[16];
484 | }LOGOUT_REQUEST , *PLOGOUT_REQUEST;
485 |
486 | //0x26
487 | struct _LOGOUT_RESPONSE
488 | {
489 | UCHAR Opcode:6;
490 | UCHAR Reserved1:2;
491 |
492 | UCHAR Reserved2:7;
493 | UCHAR Final:1;
494 |
495 | UCHAR Response;
496 | UCHAR Reserved3;
497 |
498 | UCHAR TotalAHSLength;
499 | UCHAR DataSegmentLength[3];
500 |
501 | UCHAR Reserved4[8];
502 |
503 | UCHAR InitiatorTaskTag[4];
504 | UCHAR Reserved5[4];
505 | UCHAR StatSN[4];
506 |
507 | UCHAR ExpCmdSN[4];
508 | UCHAR MaxCmdSN[4];
509 |
510 | UCHAR Reserved6[4];
511 | UCHAR Time2Wait[2];
512 | UCHAR Time2Retain[2];
513 | UCHAR Reserved7[4];
514 |
515 | }LOGOUT_RESPONSE , *PLOGOUT_RESPONSE;
516 |
517 | //0x10
518 | struct _SNACK
519 | {
520 | UCHAR Opcode:6;
521 | UCHAR Reserved1:2;
522 |
523 | UCHAR Type:4;
524 | UCHAR Reserved2:3;
525 | UCHAR Final:1;
526 |
527 | UCHAR Reserved3[2];
528 |
529 | UCHAR TotalAHSLength;
530 | UCHAR DataSegmentLength[3];
531 | union
532 | {
533 | UCHAR LUN[8];
534 | UCHAR Reserved4[8];
535 | };
536 | UCHAR InitiatorTaskTag[4];
537 | union
538 | {
539 | UCHAR TargetTransferTag[4];
540 | UCHAR SNACKTag[4];
541 | };
542 | UCHAR Reserved5[4];
543 | UCHAR ExpStatSN[4];
544 | UCHAR Reserved6[8];
545 | UCHAR BegRun[4];
546 | UCHAR RunLength[4];
547 |
548 | }SNACK , *PSNACK;
549 |
550 | //0x3f
551 | struct _REJECT
552 | {
553 | UCHAR Opcode:6;
554 | UCHAR Reserved1:2;
555 |
556 | UCHAR Reserved2:7;
557 | UCHAR Final:1;
558 |
559 | UCHAR Reason;
560 | UCHAR Reserved3;
561 |
562 | UCHAR TotalAHSLength;
563 | UCHAR DataSegmentLength[3];
564 | UCHAR Reserved4[8];
565 | UCHAR FFFF[4];
566 |
567 | UCHAR StatSN[4];
568 | UCHAR ExpCmdSN[4];
569 | UCHAR MaxCmdSN[4];
570 | union
571 | {
572 | UCHAR DataSN[4];
573 | UCHAR R2TSN[4];
574 | UCHAR Reserved5[4];
575 | };
576 | UCHAR Reserved6[8];
577 |
578 | }REJECT , *PREJECT;
579 |
580 | //0x00
581 | struct _NOP_OUT
582 | {
583 | UCHAR Opcode:6;
584 | UCHAR Immediate:1;
585 | UCHAR Reserved1:1;
586 |
587 | UCHAR Reserved2:7;
588 | UCHAR Final:1;
589 | UCHAR Reserved3[2];
590 |
591 | UCHAR TotalAHSLength;
592 | UCHAR DataSegmentLength[3];
593 | union
594 | {
595 | UCHAR LUN[8];
596 | UCHAR Reserved4[8];
597 | };
598 | UCHAR InitiatorTaskTag[4];
599 | UCHAR TargetTransferTag[4];
600 | UCHAR CmdSN[4];
601 | UCHAR ExpStatSN[4];
602 | UCHAR Reserved5[16];
603 | }NOP_OUT , *PNOP_OUT;
604 |
605 | //0x20
606 | struct _NOP_IN
607 | {
608 | UCHAR Opcode:6;
609 | UCHAR Reserved1:2;
610 |
611 | UCHAR Reserved2:7;
612 | UCHAR Final:1;
613 | UCHAR Reserved3[2];
614 |
615 | UCHAR TotalAHSLength;
616 | UCHAR DataSegmentLength[3];
617 | union
618 | {
619 | UCHAR LUN[8];
620 | UCHAR Reserved4[8];
621 | };
622 | UCHAR InitiatorTaskTag[4];
623 | UCHAR TargetTransferTag[4];
624 | UCHAR StatSN[4];
625 | UCHAR ExpCmdSN[4];
626 | UCHAR MaxCmdSN[4];
627 | UCHAR Reserved5[12];
628 | }NOP_IN , *PNOP_IN;
629 |
630 | }BHS , *PBHS;
631 |
632 | typedef struct _AHS
633 | {
634 | UCHAR AHSLength[2];
635 | UCHAR AHSType;
636 | UCHAR AHS_spec[1];
637 | }AHS, *PAHS;
638 |
639 | #define AHS_TYPE_EX_CDB 0x01
640 | #define AHS_TYPE_BIDIR_READ_LENGTH 0x02
641 |
642 | //
643 | // Keys
644 | //
645 |
646 | #define KEY_DIR_INITIATOR 0x00000001
647 | #define KEY_DIR_TARGET 0x00000002
648 | #define KEY_DIR_BOTH (KEY_DIR_INITIATOR|KEY_DIR_TARGET)
649 | #define KEY_DIR_MASK KEY_DIR_BOTH
650 |
651 | #define KEY_PHASE_IALL 0x00000004 //by Initiator , All phases
652 | #define KEY_PHASE_TALL 0x00000008 //by Target , All phases
653 |
654 | #define KEY_PHASE_ILO 0x00000010 //by Initiator , Leading Connection Only
655 | #define KEY_PHASE_IIO 0x00000020 //by Initiator , Initialization only
656 | #define KEY_PHASE_ISEC 0x00000040 //by Initiator , Security Nego Stage only
657 | #define KEY_PHASE_IFFPO 0x00000080 //by Initiator , Full Feature Phase only
658 |
659 | #define KEY_PHASE_IMASK (KEY_PHASE_ILO|KEY_PHASE_IIO|KEY_PHASE_IFFPO|KEY_PHASE_IALL)
660 |
661 | #define KEY_PHASE_TLO 0x00000100 //by Target , Leading Connection only
662 | #define KEY_PHASE_TIO 0x00000200
663 | #define KEY_PHASE_TSEC 0x00000400
664 | #define KEY_PHASE_TFFPO 0x00000800
665 |
666 | #define KEY_PHASE_TMASK (KEY_PHASE_TLO|KEY_PHASE_TIO|KEY_PHASE_TFFPO|KEY_PHASE_TALL)
667 |
668 | #define KEY_DECLARATIVE 0x00001000 //
669 |
670 | #define KEY_SCOPE_CO 0x00002000 //Connection wide
671 | #define KEY_SCOPE_SW 0x00004000 //Session wide
672 |
673 | #define KEY_IRRELEVANT_WHEN_DISCOVERY 0x00008000
674 |
675 | #define KEY_FUNC_MIN 0x00010000
676 | #define KEY_FUNC_MAX 0x00020000
677 | #define KEY_FUNC_OR 0x00040000
678 | #define KEY_FUNC_AND 0x00080000
679 |
680 | #define KEY_TYPE_STRING 0x00100000
681 | #define KEY_TYPE_BOOLEAN 0x00200000
682 | #define KEY_TYPE_NUMBER 0x00400000
683 | #define KEY_TYPE_LOV 0x00800000
684 | #define KEY_TYPE_BINARY_NUMBER 0x01000000
685 |
686 | #define KEY_DEREGISTERED 0x10000000
687 |
688 | #define KEY_NEGO_FAIL_INGORE 0x01
689 | #define KEY_NEGO_FAIL_CLOSE 0x02
690 |
691 | #define KEY_NEGO_MAX_RETRIES 0x01
692 |
693 | typedef struct _KEY_VALUE KEY_VALUE , *PKEY_VALUE;
694 |
695 | typedef VOID (*KEYHANDLER)(KeyVal , ConInfo , Questions , Answers );
696 |
697 | typedef struct _KEY_META
698 | {
699 | PUCHAR Key;
700 | UCHAR KeyLen;
701 | BOOLEAN RngValid;
702 | ULONG Low , High;
703 | ULONG Attrs;
704 | UCHAR NegoFailAction:2;
705 | UCHAR NegoRetries:6;
706 | KEYHANDLER Handler;
707 | }KEY_META , *PKEY_META;
708 |
709 | #define PiKeyName(K) (PiKeys[K].Key)
710 | #define PiKeyAttrs(K) (PiKeys[K].Attrs)
711 | #define PiIsKeyDeclarative(K) (PiKeys[K].Attrs & KEY_DECLARATIVE)
712 | #define PiIsKeyBool(K) (PiKeys[K].Attrs & KEY_TYPE_BOOLEAN)
713 | #define PiIsKeyString(K) (PiKeys[K].Attrs & KEY_TYPE_STRING)
714 | #define PiIsKeyLov(K) (PiKeys[K].Attrs & KEY_TYPE_LOV)
715 | #define PiIsKeyNumber(K) (PiKeys[K].Attrs & KEY_TYPE_NUMBER)
716 |
717 | #define PiIsKeyDeregistered(K) (PiKeys[K].Attrs & KEY_DEREGISTERED)
718 |
719 | typedef enum _KEY_NAME KEY_NAME;
720 |
721 | typedef struct _KEY_VALUE
722 | {
723 | LIST_ENTRY Vals;
724 | ULONG Size;
725 | ULONG Flags;
726 | UCHAR Formal , Pending;
727 |
728 | struct _Key
729 | {
730 | KEY_NAME D; //Predefined
731 | union
732 | {
733 | PUCHAR U; //Unknown
734 | };
735 | }Key;
736 | /*Negotiations MUST be handled as
737 | atomic operations. For example, all negotiated values go into effect
738 | after the negotiation concludes in agreement or are ignored if the
739 | negotiation fails.
740 | */
741 | union
742 | {
743 | BOOLEAN Bool;
744 | PUCHAR String;
745 | ULONG Number;
746 | struct _Lov
747 | {
748 | PUCHAR Val;
749 | PUCHAR Sel;
750 | }Lov;
751 | struct _Range
752 | {
753 | ULONG Low , High;
754 | }Range;
755 | }Value[2];
756 |
757 | UCHAR NegoRetries;
758 |
759 | ULONG Len; // Key Pair (key=val) Length , including null terminator
760 | PUCHAR FormatStr; // Formatted Key Pair String
761 | }KEY_VALUE , *PKEY_VALUE;
762 |
763 | #define KEY_F 0x00
764 | #define KEY_P 0x01
765 |
766 | #define KEY_FV(k) (k)->Value[(k)->Formal]
767 | #define KEY_PV(k) (k)->Value[(k)->Pending]
768 |
769 | //
770 | // for KEY_DECLARATIVE Key
771 | // Value[KEY_INITIATOR] store initiator value
772 | // Value[KEY_TARGET] store target value
773 | //
774 | #define KEY_I 0x00
775 | #define KEY_T 0x01
776 |
777 | #define KEY_IV(k) (k)->Value[KEY_I]
778 | #define KEY_TV(k) (k)->Value[KEY_T]
779 |
780 | #define KV(ConInfo , Key) \
781 | ( PiKeys[Key].Attrs & KEY_SCOPE_SW ? \
782 | ConInfo->Session->Parameter[Key]: \
783 | ConInfo->Parameter[KEY_CON_IDX(Key)])
784 |
785 | #define AddrKV(ConInfo , Key) \
786 | ( PiKeys[Key].Attrs & KEY_SCOPE_SW ? \
787 | &ConInfo->Session->Parameter[Key]: \
788 | &ConInfo->Parameter[KEY_CON_IDX(Key)])
789 |
790 | // KEY_VALUE + FormatStr
791 | #define PiAllocateKeyValFormatStr(Len) PiAllocateKeyVal(0,0,Len)
792 | // KEY_VALUE + Value.String
793 | #define PiAllocateKeyValStr(Len,Len2) PiAllocateKeyVal(Len,Len2,0)
794 | #define PiAllocateKeyValStr0(Len) PiAllocateKeyVal(Len,0,0)
795 | #define PiAllocateKeyValStr1(Len) PiAllocateKeyVal(0,Len,0)
796 | // KEY_VALUE
797 | #define PiAllocateKeyValue() PiAllocateKeyVal(0,0,0)
798 | // This function should put here , but just for convenience
799 | PKEY_VALUE PiAllocateKeyVal(ULONG StrLen , ULONG StrLen2 , ULONG StrLen3);
800 |
801 | //Key nego states
802 | #define KEY_Defaulted 0x00000001
803 | #define KEY_Proposed 0x00000002
804 | #define KEY_Pending 0x00000004
805 | #define KEY_Agreed 0x00000008
806 | #define KEY_STATE_MASK (KEY_Defaulted | KEY_Proposed | KEY_Pending |KEY_Agreed )
807 |
808 | #define KEY_Formatted 0x00000010
809 | // Number Format
810 | #define KEY_FMT_NUM_DEC 0x00000020
811 | #define KEY_FMT_NUM_HEX 0x00000040
812 | #define KEY_FMT_NUM_BASE64 0x00000080
813 | // Format Pending Value
814 | #define KEY_FMT_PENDING 0x00000100
815 |
816 | #define KEY_Illegal 0x00800000
817 | #define KEY_Irrelevant 0x01000000
818 | #define KEY_Reject 0x02000000
819 | #define KEY_None 0x04000000
820 | //The Value is "NotUnderstood"
821 | #define KEY_NotUnderstood 0x08000000
822 | //The Key is NotUnderstood
823 | #define KEY_NotUnderstood2 0x10000000
824 |
825 | // Key Indexes
826 |
827 | typedef enum _KEY_NAME
828 | {
829 | KEY_MaxConnections = 0 ,
830 | KEY_SendTargets ,
831 | KEY_TargetName ,
832 | KEY_InitiatorName,
833 | KEY_TargetAlias ,
834 | KEY_InitiatorAlias,
835 | KEY_TargetAddress,
836 | KEY_TargetPortalGroupTag,
837 | KEY_InitialR2T ,
838 | KEY_ImmediateData,
839 | KEY_MaxBurstLength,
840 | KEY_FirstBurstLength,
841 | KEY_DefaultTime2Wait,
842 | KEY_DefaultTime2Retain,
843 | KEY_MaxOutstandingR2T,
844 | KEY_DataPDUInOrder,
845 | KEY_DataSequenceInOrder,
846 | KEY_ErrorRecoveryLevel,
847 | KEY_SessionType,
848 |
849 | KEY_MaxSessionKey,
850 |
851 | // Followings are Connection Wide
852 | KEY_HeaderDigest,
853 | KEY_DataDigest,
854 | KEY_MaxRecvDataSegmentLength,
855 | KEY_AuthMethod,
856 |
857 | KEY_LastKey
858 | } KEY_NAME;
859 |
860 | #define KEYIN(k) \
861 | PROT_Debug(("%s Key <<< " , __FUNCTION__ )); \
862 | PiDumpKey( k )
863 |
864 | #define KEYOUT(k) \
865 | PROT_Debug(("%s Key >>> " , __FUNCTION__ )); \
866 | PiDumpKey( k )
867 |
868 | extern PKEY_META PiKeys;
869 |
870 | typedef struct _PDU PDU , *PPDU;
871 | typedef struct _uCONINFO uCONINFO,*PuCONINFO;
872 |
873 | typedef union _THREE_BYTE
874 | {
875 | struct
876 | {
877 | UCHAR Byte0;
878 | UCHAR Byte1;
879 | UCHAR Byte2;
880 | };
881 |
882 | ULONG AsULong:24;
883 |
884 | }THREE_BYTE , *PTHREE_BYTE;
885 |
886 | #define REVERSE_3BYTES(Destination, Source) { \
887 | PTHREE_BYTE d = (PTHREE_BYTE)(Destination); \
888 | PTHREE_BYTE s = (PTHREE_BYTE)(Source); \
889 | d->Byte2 = s->Byte0; \
890 | d->Byte1 = s->Byte1; \
891 | d->Byte0 = s->Byte2; \
892 | }
893 |
894 |
895 | //
896 | // Response.c
897 | //
898 | VOID
899 | PtProcessResponse (
900 | PPDU Pdu ,
901 | PuCONINFO ConInfo
902 | );
903 | //
904 | // Data.c
905 | //
906 | VOID
907 | PtProcessDataIn (
908 | PPDU Pdu ,
909 | PuCONINFO ConInfo
910 | );
911 | //
912 | // R2T.c
913 | //
914 | VOID
915 | PtProcessR2T(
916 | PPDU Pdu ,
917 | PuCONINFO ConInfo
918 | );
919 | //
920 | // Task.c
921 | //
922 | VOID
923 | PtProcessTask (
924 | PPDU Pdu ,
925 | PuCONINFO ConInfo
926 | );
927 | //
928 | // Text.c
929 | //
930 | VOID
931 | PtProcessText(
932 | PPDU Pdu ,
933 | PuCONINFO ConInfo
934 | );
935 | //
936 | // Login.c
937 | //
938 | VOID
939 | PtProcessLogin(
940 | PPDU Pdu ,
941 | PuCONINFO ConInfo
942 | );
943 |
944 | NTSTATUS
945 | PtLogin(
946 | PuCONINFO ConInfo
947 | );
948 |
949 | VOID
950 | PtProcessLogout (
951 | PPDU Pdu ,
952 | PuCONINFO ConInfo
953 | );
954 | //
955 | // Reject.c
956 | //
957 | VOID
958 | PtProcessReject (
959 | PPDU Pdu ,
960 | PuCONINFO ConInfo
961 | );
962 | //
963 | // Nop.c
964 | //
965 | VOID
966 | PtProcessNopIn (
967 | PPDU Pdu ,
968 | PuCONINFO ConInfo
969 | );
970 |
971 | VOID
972 | PtNopOut (
973 | PuCONINFO ConInfo ,
974 | BOOLEAN Echo
975 | );
976 | //
977 | // Protocol.c
978 | //
979 | NTSTATUS
980 | PtInit();
981 |
982 | NTSTATUS
983 | PtUnInit();
984 |
985 | VOID
986 | PtProcessAsyncMsg (
987 | PPDU Pdu ,
988 | PuCONINFO ConInfo
989 | );
990 |
991 | // Cmd.c
992 | PPDU
993 | PtAssembleSCSICmd (
994 | PuCONINFO ConInfo ,
995 | PUCHAR Cdb ,
996 | ULONG CdbLength ,
997 | PUCHAR DataBuffer ,
998 | ULONG WriteSize ,
999 | ULONG ReadSize,
1000 | UCHAR TaskAttr,
1001 | UCHAR Dir
1002 | );
1003 | #endif
--------------------------------------------------------------------------------
/uSCSIPort/R2T.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | PPDU PiFindPendingTask(ULONG TaskTag , PuCONINFO ConInfo , BOOLEAN Remove);
5 |
6 | __inline VOID PiSendDataOut(PuCON_CTX Ctx , PPDU CmdOrR2T );
7 |
8 | PPDU PiQueueDataInOrR2T(PuCONINFO ConInfo , PPDU Cmd , PPDU DataInOrR2T);
9 |
10 | PPDU PiAllocateDataOutPDU(
11 | PuCONINFO ConInfo , PUCHAR DataBuf , ULONG Offset, ULONG DataSize,PULONG DataSN,PPDU RefCmd);
12 |
13 | //
14 | //
15 | //
16 |
17 | VOID PtProcessR2T(PPDU Pdu , PuCONINFO ConInfo)
18 | {
19 | PPDU Cmd;
20 | PSESSION Session;
21 | PuCON_CTX Ctx;
22 | FOUR_BYTE ITT;
23 |
24 | Ctx = ConInfo->ConCtx;
25 | Session = ConInfo->Session;
26 |
27 | InterlockedIncrement ( (PLONG)&Session->R2TCount );
28 |
29 | REVERSE_BYTES ( &ITT , &Pdu->Bhs->R2T.InitiatorTaskTag);
30 | Cmd = PiFindPendingTask ( ITT.AsULong , ConInfo , FALSE);
31 | Pdu->Cmd = Cmd;
32 |
33 | Pdu = PiQueueDataInOrR2T ( ConInfo , Cmd , Pdu );
34 | if ( Pdu )
35 | {
36 | TpQueueR2TPDU ( Ctx , Pdu );
37 | }
38 | }
39 |
40 | //
41 | // Sender for R2Ts
42 | //
43 |
44 | VOID PiR2TWorker(IN PVOID Parameter)
45 | {
46 | NTSTATUS Status;
47 | PSESSION Session;
48 | PWORKER_THREAD_CTX Tctx;
49 | PuCONINFO ConInfo;
50 | PuCON_CTX Ctx;
51 | PLIST_ENTRY R2TEnt;
52 | PPDU R2T, Cmd, DataOut;
53 | ULONG DesiredDataTransferLength;
54 | ULONG MaxRecvDataSegmentLength , MaxBurstLength;
55 | ULONG Offset = 0 ;
56 |
57 | Status = STATUS_SUCCESS;
58 |
59 | Tctx = (PWORKER_THREAD_CTX)Parameter;
60 | Ctx = Tctx->Ctx;
61 | ConInfo = Ctx->ConInfo;
62 | Session = ConInfo->Session;
63 |
64 | MaxRecvDataSegmentLength = KEY_TV(KV(ConInfo , KEY_MaxRecvDataSegmentLength)).Number;
65 | MaxBurstLength = KEY_FV(KV(ConInfo,KEY_MaxBurstLength)).Number;
66 | /*
67 | Within a connection, outstanding R2Ts MUST be fulfilled by the
68 | initiator in the order in which they were received
69 | */
70 | while (TRUE )
71 | {
72 | Status = KeWaitForSingleObject ( &Ctx->R2TEvent ,
73 | Executive ,
74 | KernelMode ,
75 | FALSE ,
76 | NULL );
77 |
78 | KeClearEvent(&Ctx->R2TEvent);
79 |
80 | while ( R2TEnt = ExInterlockedRemoveHeadList ( &Ctx->R2Ts , &Ctx->R2TLock ) )
81 | {
82 | R2T = (PPDU)CONTAINING_RECORD ( R2TEnt , PDU , PDUList );
83 | InitializeListHead ( &R2T->PDUList);
84 | Cmd = R2T->Cmd;
85 | /*
86 | The Desired Data
87 | Transfer Length MUST NOT be 0 and MUST not exceed MaxBurstLength p143
88 | */
89 | REVERSE_BYTES ( &DesiredDataTransferLength ,
90 | &R2T->Bhs->R2T.DesiredDataTransferLength);
91 | REVERSE_BYTES ( &Offset , &R2T->Bhs->R2T.BufferOffset);
92 |
93 | #ifdef STRICT_PROT_CHECK
94 | if ( DesiredDataTransferLength > MaxBurstLength || !DesiredDataTransferLength)
95 | PiProtError( ConInfo , __FUNCTION__ );
96 | #endif
97 | /*
98 | DbgPrint("%s DataBuffer=0x%X Offset=0x%X DesiredDataTransferLength=0x%X\n",
99 | __FUNCTION__ , Cmd->DataBuffer,Offset,DesiredDataTransferLength);*/
100 | DataOut = PiAllocateDataOutPDU ( ConInfo ,
101 | Cmd->DataBuffer,
102 | Offset ,
103 | DesiredDataTransferLength,
104 | &R2T->DataSN ,
105 | R2T );
106 |
107 | InsertTailList ( &R2T->DataOut , &DataOut->DataOut );
108 |
109 | InterlockedDecrement ( (PLONG)&Session->R2TCount );
110 |
111 | PiSendDataOut ( Ctx , R2T );
112 | }
113 | }
114 |
115 | ExFreePoolWithTag ( Tctx , USCSI_TAG );
116 | //Ctx->WorkItemFlags |= CONCTX_R2T_SAFE;
117 | }
--------------------------------------------------------------------------------
/uSCSIPort/Reject.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | VOID PtProcessReject ( PPDU Pdu , PuCONINFO ConInfo)
5 | {
6 | PROT_Debug(("%s ConInfo 0x%p Pdu 0x%p\n" , __FUNCTION__ , ConInfo , Pdu));
7 | }
--------------------------------------------------------------------------------
/uSCSIPort/Response.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | PPDU PiFindPendingTask(ULONG TaskTag , PuCONINFO ConInfo , BOOLEAN Remove);
5 |
6 | BOOLEAN PiCheckDataInHole(PPDU Cmd );
7 |
8 | //
9 | //
10 | //
11 | BOOLEAN PiCheckCmdComplete( PPDU Cmd );
12 |
13 | VOID PtProcessResponse(PPDU Pdu, PuCONINFO ConInfo)
14 | {
15 | PPDU Cmd;
16 | FOUR_BYTE ITT , ExpDataSN , BRC , RC;
17 |
18 | REVERSE_BYTES ( &BRC , &Pdu->Bhs->SCSI_RESPONSE.BiReadResidualCount);
19 | REVERSE_BYTES ( &RC , &Pdu->Bhs->SCSI_RESPONSE.ResidualCount);
20 |
21 | REVERSE_BYTES ( &ITT , &Pdu->Bhs->SCSI_RESPONSE.InitiatorTaskTag);
22 | Cmd = PiFindPendingTask ( ITT.AsULong , ConInfo , FALSE);
23 | Pdu->Cmd = Cmd;
24 | /*
25 | DbgPrint(
26 | "%s ITT=0x%X Pdu=0x%p UOuo=(%d%d%d%d) Response=0x%X Status=0x%X BRC=0x%X RC=0x%X\n" ,
27 | __FUNCTION__ ,
28 | ITT.AsULong ,
29 | Pdu,
30 | Pdu->Bhs->SCSI_RESPONSE.U,
31 | Pdu->Bhs->SCSI_RESPONSE.O,
32 | Pdu->Bhs->SCSI_RESPONSE.u,
33 | Pdu->Bhs->SCSI_RESPONSE.o,
34 | Pdu->Bhs->SCSI_RESPONSE.Response,
35 | Pdu->Bhs->SCSI_RESPONSE.Status,
36 | BRC.AsULong ,
37 | RC.AsULong);*/
38 |
39 | REVERSE_BYTES ( &ExpDataSN , &Pdu->Bhs->SCSI_RESPONSE.ExpDataSN);
40 | Cmd->ExpDataSN = ExpDataSN.AsULong;
41 | //
42 | // Queue Response , its processing may be delayed
43 | // if there are any missing Data-In/R2T(s)
44 | //
45 | InsertTailList ( &Cmd->Resps , &Pdu->Resps );
46 |
47 | if ( !PiCheckDataInHole ( Cmd ) )
48 | {
49 | Cmd->Flags |= PDU_F_CMD_CAN_COMPLETE;
50 | TpQueuePendingCompleteCmd ( Cmd->ConCtx , Cmd );
51 | }
52 | }
--------------------------------------------------------------------------------
/uSCSIPort/SNACK.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | VOID PtSNACK (PuCONINFO ConInfo)
5 | {
6 | PPDU Pdu;
7 |
8 | Pdu = TpAllocatePDU ( ConInfo->ConCtx , OP_SNACK_REQ , 0 , 0 );
9 | }
--------------------------------------------------------------------------------
/uSCSIPort/SOURCES:
--------------------------------------------------------------------------------
1 | TARGETNAME=uSCSIPort
2 | TARGETTYPE=EXPORT_DRIVER
3 | TARGETPATH=..\obj
4 | TARGETLIBS=$(SDK_LIB_PATH)\tdi.lib
5 | INCLUDES=.
6 | SOURCES=uSCSI.c \
7 | Transport.c \
8 | TransUtils.c \
9 | Protocol.c \
10 | ProtUtils.c \
11 | Key.c \
12 | Login.c \
13 | Discover.c \
14 | Text.c \
15 | Handler.c \
16 | Nop.c \
17 | Cmd.c \
18 | Data.c \
19 | R2T.c \
20 | Reject.c \
21 | Response.c \
22 | Task.c
23 |
24 |
--------------------------------------------------------------------------------
/uSCSIPort/Task.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | VOID PtProcessTask ( PPDU Pdu , PuCONINFO ConInfo)
5 | {
6 | PROT_Debug(("%s ConInfo 0x%p Pdu 0x%p\n" , __FUNCTION__ , ConInfo , Pdu));
7 | }
--------------------------------------------------------------------------------
/uSCSIPort/Text.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | VOID PiProcessKey( PPDU Pdu , PuCONINFO ConInfo , BOOLEAN AllocatePDU ,UCHAR Opcode);
5 |
6 | VOID PiAnswerPdu( PPDU Pdu , PuCONINFO ConInfo , UCHAR Opcode );
7 |
8 | BOOLEAN PiCanTxtComplete (PuCONINFO ConInfo );
9 |
10 | VOID PiProtError (PuCONINFO ConInfo , PUCHAR Func );
11 |
12 | #define PiAnswerTextPdu( Pdu , ConInfo) \
13 | PiAnswerPdu ( Pdu , ConInfo , OP_TXT_REQ)
14 |
15 | #define PiTextProcessKey(Pdu , ConInfo , AllocatePDU ) \
16 | PiProcessKey (Pdu , ConInfo , AllocatePDU , OP_TXT_REQ)
17 |
18 | //
19 | //
20 | //
21 |
22 | VOID PtProcessText( PPDU Pdu , PuCONINFO ConInfo)
23 | {
24 | PPDU LPdu = NULL;
25 |
26 | PROT_Debug(("%s ConInfo 0x%p Pdu 0x%p\n" , __FUNCTION__ , ConInfo , Pdu));
27 |
28 | if ( ConInfo->Answer )
29 | {
30 | #ifdef STRICT_PROT_CHECK
31 | if ( DataSegLen )
32 | PiProtError ( ConInfo , __FUNCTION__ );
33 | #endif
34 | goto Answer;
35 | }
36 |
37 | /*An initiator receiving a Text or Login
38 | Response with the C bit set to 1 MUST answer with a Text or Login
39 | Request with no data segment (DataSegmentLength 0).*/
40 | if ( Pdu->Bhs->TXT_RESPONSE.Continue )
41 | {
42 | #ifdef STRICT_PROT_CHECK
43 | if ( Pdu->Bhs->TXT_RESPONSE.Transit )
44 | PiProtError( ConInfo , __FUNCTION__ );
45 | #endif
46 | if ( !ConInfo->Logical )
47 | ConInfo->Logical = Pdu; //Head
48 | else
49 | // Part of
50 | InsertTailList ( &ConInfo->Logical->Continue, &Pdu->Continue );
51 | goto Answer;
52 | }
53 | //
54 | // Logical Pdu completed
55 | //
56 | if (ConInfo->Logical )
57 | {
58 | LPdu = ConInfo->Logical;
59 | ConInfo->Logical = NULL;
60 | }
61 | else
62 | LPdu = Pdu;
63 |
64 | PiTextProcessKey ( LPdu ,
65 | ConInfo ,
66 | /*
67 | A Text Response with the F bit set to 1 MUST NOT contain key=value
68 | pairs that may require additional answers from the initiator
69 | */
70 | !LPdu->Bhs->TXT_RESPONSE.Final );
71 | #ifdef STRICT_PROT_CHECK
72 | if ( ConInfo->TextState == TXT_STAT_STARTED && Pdu->Bhs->TXT_RESPONSE.Final)
73 | {
74 | PiProtError (ConInfo , __FUNCTION__);
75 | }
76 | else if
77 | #else
78 | if
79 | #endif
80 | ( ConInfo->TextState == TXT_STAT_STARTED &&
81 | !Pdu->Bhs->TXT_RESPONSE.Final)
82 | {
83 | if ( PiCanTxtComplete(ConInfo) )
84 | {
85 | PROT_Debug(("%s Completion Requested\n" , __FUNCTION__));
86 | ConInfo->TextState = TXT_STAT_PENDING_COMPLETE;
87 | }
88 | }
89 | else if ( ConInfo->TextState == TXT_STAT_PENDING_COMPLETE &&
90 | Pdu->Bhs->TXT_RESPONSE.Final )
91 | {
92 | // End Conversation
93 | PROT_Debug(("%s Completion Agreed\n" , __FUNCTION__));
94 | ConInfo->TextState = TXT_STAT_IDLE;
95 | return;
96 | }
97 | else if ( ConInfo->TextState == TXT_STAT_PENDING_COMPLETE &&
98 | !Pdu->Bhs->TXT_RESPONSE.Final)
99 | {
100 | //NewPdu->Bhs->TXT_REQUEST.Final = 1;
101 | }
102 |
103 | Answer:
104 |
105 | PiAnswerTextPdu( Pdu , ConInfo );
106 | }
107 |
108 | /*
109 | Logic for ending a Text conversation
110 | */
111 | BOOLEAN PiCanTxtComplete (PuCONINFO ConInfo )
112 | {
113 | if (ConInfo->MoreWorks)
114 | return FALSE;
115 |
116 | return TRUE;
117 | }
--------------------------------------------------------------------------------
/uSCSIPort/Transport.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | BOOLEAN TiVerifyDataDigest( IN PuCON_CTX Ctx, IN PPDU Pdu);
5 |
6 | BOOLEAN TiVerifyHeaderDigest( IN PuCON_CTX Ctx, IN PPDU Pdu);
7 |
8 | PPDU TiAllocatePDU( IN PuCON_CTX Ctx );
9 |
10 | NTSTATUS PiCompletePDU (IN PDEVICE_OBJECT DevObj , IN PIRP Irp , IN PVOID Ctx);
11 |
12 | //
13 | // PDU Assembler
14 | //
15 |
16 | // Called at DISPATCH_LEVEL
17 | // for Now PDU buffer is allocated from NonPagedPool
18 |
19 | VOID TiReceive(
20 | IN PVOID TdiEventContext,
21 | IN CONNECTION_CONTEXT ConnectionContext,
22 | IN ULONG ReceiveFlags,
23 | IN ULONG BytesIndicated,
24 | IN ULONG BytesAvailable,
25 | OUT ULONG *BytesTaken,
26 | IN PVOID Tsdu,
27 | OUT PIRP *IoRequestPacket)
28 | {
29 | NTSTATUS Status;
30 | PUCHAR PTsdu;
31 | PuCON_CTX Ctx;
32 | PPDU Pdu;
33 | ULONG Remaining;
34 | ULONG Copied;
35 | THREE_BYTE DataSegmentLength;
36 |
37 | Status = STATUS_SUCCESS;
38 | Ctx = (PuCON_CTX)ConnectionContext;
39 | PTsdu = (PUCHAR)Tsdu;
40 | /*
41 | KdPrintEx((DPFLTR_USCSI,DBG_TRANSPORT,
42 | "%s ReceiveFlags 0x%X BytesIndicated 0x%X BytesAvailable 0x%X Tsdu 0x%p\n" ,
43 | __FUNCTION__ ,
44 | ReceiveFlags ,
45 | BytesIndicated ,
46 | BytesAvailable,
47 | Tsdu));*/
48 |
49 | Remaining = BytesIndicated;
50 |
51 | while ( Remaining > 0)
52 | {
53 | if ( !Ctx->PendingPDU )
54 | {
55 | Pdu = TiAllocatePDU (Ctx);
56 | KdPrintEx((DPFLTR_USCSI,DBG_TRANSPORT,"%s Process Pdu 0x%p\n" , __FUNCTION__,Pdu ));
57 | }
58 | else
59 | Pdu = Ctx->PendingPDU;
60 |
61 | //BHS
62 | if (Pdu->Bytes < BHS_SIZE)
63 | {
64 | Copied = min ( (BHS_SIZE - Pdu->Bytes) , Remaining);
65 | RtlCopyMemory ( (PUCHAR)Pdu->Bhs + Pdu->Bytes , PTsdu , Copied );
66 |
67 | PTsdu += Copied;
68 | Remaining -= Copied;
69 | Pdu->Bytes += Copied;
70 | *BytesTaken += Copied;
71 |
72 | if (Pdu->Bytes < BHS_SIZE)
73 | Ctx->PendingPDU = Pdu; //Pending for BHS
74 | else
75 | {
76 | // BHS Completed , allocate buffer for AHS or DATA
77 | if (!TiVerifyHeaderDigest( Ctx , Pdu ) )
78 | {
79 | // Close connection and return
80 | }
81 | /*
82 | TotalAHSLength:
83 |
84 | Total length of all AHS header segments in units of four byte words
85 | including padding, if any. p115
86 | */
87 | Pdu->BufferSize = Pdu->Bhs->GENERICBHS.TotalAHSLength << 2;
88 |
89 | /*
90 | DataSegmentLength:
91 |
92 | This is the data segment payload length in bytes (excluding padding).
93 | The DataSegmentLength MUST be 0 whenever the PDU has no data segment. p115
94 |
95 | The (optional) Data Segment contains PDU associated data. Its
96 | payload effective length is provided in the BHS field -
97 | DataSegmentLength. The Data Segment is also padded to an integer
98 | number of 4 byte words. p118
99 | */
100 | REVERSE_3BYTES ( &DataSegmentLength , &Pdu->Bhs->GENERICBHS.DataSegmentLength);
101 | Pdu->BufferSize += DataSegmentLength.AsULong;
102 |
103 | if ( Pdu->BufferSize &0x3 )
104 | {
105 | Pdu->BufferSize &= ~0x3;
106 | Pdu->BufferSize += 0x4;
107 | }
108 |
109 | if ( Pdu->BufferSize )
110 | {
111 | Pdu->Buffer = ExAllocatePoolWithTag ( NonPagedPool, Pdu->BufferSize, USCSI_TAG );
112 | Ctx->PendingPDU = Pdu; //Pending for AHS and DATA
113 | }
114 | else
115 | // PDU Completed
116 | goto QueuePdu;
117 | }
118 | }
119 | //AHS and Data
120 | else
121 | {
122 | Copied = min ( (Pdu->BufferSize + BHS_SIZE - Pdu->Bytes) , Remaining );
123 | RtlCopyMemory ( Pdu->Buffer + ( Pdu->Bytes - BHS_SIZE ) , PTsdu , Copied);
124 |
125 | PTsdu += Copied;
126 | Remaining -= Copied;
127 | Pdu->Bytes += Copied;
128 | *BytesTaken += Copied;
129 |
130 | if (Pdu->Bytes < Pdu->BufferSize + BHS_SIZE )
131 | {
132 | Ctx->PendingPDU = Pdu; //Pending for AHS and DATA
133 | continue;
134 | }
135 | //
136 | // Complete a PDU , queue it
137 | //
138 | QueuePdu:
139 |
140 | if ( Pdu->Bhs->GENERICBHS.TotalAHSLength )
141 | Pdu->Ahs = Pdu->Buffer;
142 |
143 | REVERSE_3BYTES ( &DataSegmentLength , &Pdu->Bhs->GENERICBHS.DataSegmentLength);
144 | if ( DataSegmentLength.AsULong )
145 | Pdu->Data = Pdu->Buffer + Pdu->Bhs->GENERICBHS.TotalAHSLength;
146 |
147 | Ctx->PendingPDU = NULL;
148 | //
149 | KdPrintEx((DPFLTR_USCSI,DBG_TRANSPORT,
150 | "%s Pdu 0x%X Opcode 0x%X BufferSize 0x%X\n" ,
151 | __FUNCTION__,
152 | Pdu,
153 | Pdu->Bhs->GENERICBHS.Opcode,
154 | Pdu->BufferSize));
155 |
156 | KeQuerySystemTime ( &Pdu->ReceivingTime );
157 |
158 | if ( TiVerifyDataDigest ( Ctx , Pdu) )
159 | TpQueueInPDU ( Ctx , Pdu );
160 | }
161 | }
162 | }
163 |
164 | //
165 | //
166 | //
167 |
168 | UCHAR TiDataPadding[4];
169 | ULONG TiAllocateMdl (IN PPDU Pdu , IN PIRP Irp)
170 | {
171 | PMDL Mdl;
172 | ULONG SendLen = 0 , DataSize = 0;
173 | UCHAR PaddingLen;
174 | THREE_BYTE DataSegmentLength;
175 |
176 | Mdl = IoAllocateMdl ( Pdu->Bhs, BHS_SIZE, FALSE , FALSE , Irp );
177 | __try
178 | {
179 | MmProbeAndLockPages ( Mdl , KernelMode , IoReadAccess );
180 | }
181 | __except (EXCEPTION_EXECUTE_HANDLER)
182 | {
183 | DbgPrint("%s Exception 0x%X" , __FUNCTION__ , GetExceptionCode() );
184 | }
185 |
186 | SendLen += BHS_SIZE;
187 |
188 | if ( Pdu->Ahs )
189 | {
190 | Mdl = IoAllocateMdl ( Pdu->Ahs ,
191 | Pdu->Bhs->GENERICBHS.TotalAHSLength << 2,
192 | TRUE ,
193 | FALSE ,
194 | Irp );
195 | __try
196 | {
197 | MmProbeAndLockPages ( Mdl , KernelMode , IoReadAccess );
198 | }
199 | __except (EXCEPTION_EXECUTE_HANDLER)
200 | {
201 | DbgPrint("%s Exception 0x%X" , __FUNCTION__ , GetExceptionCode());
202 | }
203 |
204 | SendLen += Pdu->Bhs->GENERICBHS.TotalAHSLength << 2;
205 | }
206 |
207 | if ( Pdu->Data )
208 | {
209 | REVERSE_3BYTES ( &DataSegmentLength , &Pdu->Bhs->GENERICBHS.DataSegmentLength );
210 |
211 | Mdl = IoAllocateMdl ( Pdu->Data ,
212 | DataSegmentLength.AsULong ,
213 | TRUE ,
214 | FALSE ,
215 | Irp );
216 | __try
217 | {
218 | MmProbeAndLockPages ( Mdl , KernelMode , IoReadAccess );
219 | }
220 | __except (EXCEPTION_EXECUTE_HANDLER)
221 | {
222 | DbgPrint("%s Exception 0x%X" , __FUNCTION__ , GetExceptionCode());
223 | }
224 | //
225 | // Padding if needed
226 | //
227 | if ( PaddingLen = DataSegmentLength.AsULong & 0x3 )
228 | {
229 | DataSegmentLength.AsULong &= ~0x3;
230 | DataSegmentLength.AsULong += 0x4;
231 |
232 | Mdl = IoAllocateMdl ( TiDataPadding ,
233 | 4 - PaddingLen ,
234 | TRUE ,
235 | FALSE ,
236 | Irp );
237 | __try
238 | {
239 | MmProbeAndLockPages ( Mdl , KernelMode , IoReadAccess );
240 | }
241 | __except (EXCEPTION_EXECUTE_HANDLER)
242 | {
243 | DbgPrint("%s Exception 0x%X" , __FUNCTION__ , GetExceptionCode() );
244 | }
245 | }
246 |
247 | SendLen += DataSegmentLength.AsULong;
248 | }
249 |
250 | return SendLen;
251 | }
252 |
253 | //
254 | //
255 | //
256 |
257 | VOID TiCheckCmdWindow (IN PSESSION Session)
258 | {
259 | KIRQL OldIrql;
260 |
261 | KeAcquireSpinLock ( &Session->WindowLock , &OldIrql );
262 |
263 | if ( Session->CmdSN > Session->MaxCmdSN)
264 | {
265 | KeReleaseSpinLock ( &Session->WindowLock , OldIrql );
266 | KeWaitForSingleObject ( &Session->WindowEvent , Executive , KernelMode , FALSE , NULL );
267 | KeClearEvent ( &Session->WindowEvent );
268 | }
269 |
270 | KeReleaseSpinLock ( &Session->WindowLock , OldIrql );
271 | }
272 |
273 | //
274 | // Sender for outgoing PDUs
275 | //
276 |
277 | VOID TiSender(IN PVOID Parameter)
278 | {
279 | NTSTATUS Status;
280 | PWORKER_THREAD_CTX Tctx;
281 | PuCONINFO ConInfo;
282 | PuCON_CTX Ctx;
283 | PPDU Pdu;
284 | PIRP Irp;
285 | PDEVICE_OBJECT DevObj;
286 | PLIST_ENTRY Entry;
287 | LONG DataSize = 0 , SendLen = 0;
288 | ULONG CmdSN , ExpStatSN;
289 | FOUR_BYTE ITT;
290 | KEVENT Event;
291 | IO_STATUS_BLOCK IoStatus;
292 |
293 | Status = STATUS_SUCCESS;
294 | Tctx = (PWORKER_THREAD_CTX)Parameter;
295 | Ctx = Tctx->Ctx;
296 | ConInfo = Ctx->ConInfo;
297 |
298 | DevObj = IoGetRelatedDeviceObject (ConInfo->ConEpObj);
299 |
300 | while ( TRUE )
301 | {
302 | Status = KeWaitForSingleObject ( &Ctx->OutEvent ,
303 | Executive ,
304 | KernelMode ,
305 | FALSE ,
306 | NULL );
307 |
308 | KeClearEvent ( &Ctx->OutEvent );
309 |
310 | while ( Entry = ExInterlockedRemoveHeadList ( &Ctx->OutPDU , &Ctx->OutLock ) )
311 | {
312 | Pdu = CONTAINING_RECORD ( Entry , PDU , PDUList );
313 | InitializeListHead ( &Pdu->PDUList );
314 |
315 | KeInitializeEvent ( &Event , NotificationEvent , FALSE);
316 |
317 | Irp = TdiBuildInternalDeviceControlIrp( TDI_SEND, DevObj, NULL, &Event, &IoStatus );
318 | if (!Irp )
319 | {
320 | DbgPrint("%s Fail to allocate Irp\n" ,__FUNCTION__ );
321 | Ctx->FailedIrpAllocation++;
322 | //Retry later
323 | TpQueueOutPDU( Ctx , Pdu );
324 | continue;
325 | }
326 | // CmdSN
327 | if (Pdu->Bhs->GENERICBHS.Opcode != OP_DATA_OUT &&
328 | Pdu->Bhs->GENERICBHS.Opcode != OP_SNACK_REQ )
329 | {
330 | TiCheckCmdWindow (ConInfo->Session);
331 |
332 | if (Pdu->Bhs->GENERICBHS.Immediate)
333 | CmdSN = ConInfo->Session->CmdSN;
334 | else
335 | CmdSN = InterlockedIncrement ( (PLONG)&ConInfo->Session->CmdSN );
336 |
337 | REVERSE_BYTES ( &Pdu->Bhs->STAT_FIELDS.CmdSN , &CmdSN);
338 | }
339 | // State Sync
340 | ExpStatSN = ConInfo->ExpStatSN;
341 | REVERSE_BYTES ( &Pdu->Bhs->STAT_FIELDS.ExpStatSN ,&ExpStatSN);
342 |
343 | SendLen = TiAllocateMdl ( Pdu , Irp );
344 |
345 | REVERSE_BYTES ( &ITT , &Pdu->Bhs->STAT_FIELDS.InitiatorTaskTag );
346 | /*
347 | DbgPrint(
348 | "%s Pdu=0x%X ITT=0x%X Opcode=0x%X ScsiOpcode=0x%X Irp=0x%p SendLen=0x%X Bhs=0x%p Ahs=0x%p Data=0x%p CmdSN=0x%X\n" ,
349 | __FUNCTION__,
350 | Pdu,
351 | ITT.AsULong,
352 | Pdu->Bhs->GENERICBHS.Opcode,
353 | Pdu->Bhs->GENERICBHS.Opcode == OP_SCSI_CMD?Pdu->Bhs->SCSI_CMD.Cdb[0]:0xFF,
354 | Irp ,
355 | SendLen ,
356 | Pdu->Bhs,
357 | Pdu->Ahs,
358 | Pdu->Data,
359 | CmdSN );*/
360 |
361 | TdiBuildSend(
362 | Irp, DevObj, ConInfo->ConEpObj, PiCompletePDU, Pdu, Irp->MdlAddress, 0, SendLen);
363 |
364 | Status = IoCallDriver ( DevObj , Irp );
365 | if ( STATUS_PENDING == Status )
366 | KeWaitForSingleObject ( &Event , Executive , KernelMode , FALSE , NULL );
367 | }
368 | }
369 |
370 | KdPrintEx((DPFLTR_USCSI,DBG_TRANSPORT,"Sender(0x%x) Exited\n" , Tctx->No ));
371 |
372 | ExFreePoolWithTag ( Tctx , USCSI_TAG );
373 |
374 | }
375 |
376 | PSN TiAllocateSN ( IN PuCONINFO ConInfo );
377 |
378 | VOID TiFreeSN ( IN PuCONINFO ConInfo , IN PSN StatSN);
379 |
380 |
381 | __inline BOOLEAN TiUpdateStatSN(IN PuCONINFO ConInfo, IN ULONG Num )
382 | {
383 | PSESSION Session;
384 | PSINGLE_LIST_ENTRY StatSNEnt , StatSNEnt2 = NULL;
385 | PSN StatSN;
386 | BOOLEAN ResetTimer = FALSE;
387 |
388 | if ( !ConInfo->ExpStatSNInited )
389 | {
390 | ConInfo->ExpStatSN = Num + 1;
391 | ConInfo->ExpStatSNInited = TRUE;
392 | ResetTimer = TRUE;
393 | }
394 | // Exactly what we want
395 | else if ( ConInfo->ExpStatSN == Num )
396 | {
397 | // Expect next one
398 | ConInfo->ExpStatSN++;
399 | // Maybe the others can be acked
400 | while ( StatSNEnt = ConInfo->StatSN.Next )
401 | {
402 | StatSN = CONTAINING_RECORD ( StatSNEnt , SN , Next );
403 | if ( StatSN->SN == ConInfo->ExpStatSN )
404 | {
405 | ConInfo->ExpStatSN++;
406 | PopEntryList( &ConInfo->StatSN );
407 | TiFreeSN ( ConInfo , StatSN);
408 | ResetTimer = TRUE;
409 | continue;
410 | }
411 | break;
412 | }
413 | }
414 | // Out of order
415 | else if ( ConInfo->ExpStatSN < Num )
416 | {
417 | //
418 | // Insert , sort by StatSN
419 | //
420 | StatSNEnt = &ConInfo->StatSN;
421 |
422 | while ( StatSNEnt = StatSNEnt->Next )
423 | {
424 | StatSN = CONTAINING_RECORD ( StatSNEnt , SN , Next );
425 |
426 | StatSNEnt2 = StatSNEnt;
427 |
428 | if ( StatSN->SN < Num )
429 | break;
430 | else if ( StatSN->SN == Num )
431 | {
432 | // Duplicated Stat
433 | // Maybe Target timeouted and auto retransmit it
434 | // rarely happen
435 | ConInfo->DupStatSN++;
436 | return FALSE;
437 | }
438 | }
439 |
440 | if (!StatSNEnt2)
441 | StatSNEnt2 = &ConInfo->StatSN;
442 |
443 | StatSN = TiAllocateSN ( ConInfo );
444 | StatSN->SN = Num;
445 |
446 | PushEntryList ( StatSNEnt2 , &StatSN->Next);
447 | }
448 |
449 | else if ( ConInfo->ExpStatSN > Num )
450 | {
451 | // This is a retransmit of R2T
452 | }
453 |
454 | if (ResetTimer)
455 | {
456 | //TODO
457 | }
458 |
459 | return TRUE;
460 | }
461 |
462 |
463 | __inline VOID TiUpdateCmdWindow ( PuCONINFO ConInfo , ULONG ExpCmdSN , ULONG MaxCmdSN)
464 | {
465 | KIRQL OldIrql;
466 | PSESSION Session;
467 |
468 | Session = ConInfo->Session;
469 |
470 | KeAcquireSpinLock (&Session->WindowLock , &OldIrql );
471 |
472 | if ( ExpCmdSN > Session->ExpCmdSN )
473 | Session->ExpCmdSN = ExpCmdSN;
474 |
475 | if ( MaxCmdSN > Session->MaxCmdSN)
476 | Session->MaxCmdSN = MaxCmdSN ;
477 |
478 | KdPrintEx((DPFLTR_USCSI,DBG_TRANSPORT,
479 | "%s ExpCmdSN 0x%X MaxCmdSN 0x%X Window %d\n" ,
480 | __FUNCTION__ ,
481 | Session->ExpCmdSN,
482 | Session->MaxCmdSN,
483 | Session->MaxCmdSN - Session->ExpCmdSN ));
484 |
485 | KeReleaseSpinLock (&Session->WindowLock , OldIrql );
486 | //
487 | // TiCheckCmdWindow wait on WindowEvent
488 | //
489 | if ( Session->MaxCmdSN > Session->CmdSN)
490 | KeSetEvent ( &Session->WindowEvent , IO_NO_INCREMENT , FALSE);
491 | }
492 |
493 | //
494 | // Dispatcher for incoming PDUs
495 | //
496 |
497 | VOID TiDispatcher( IN PVOID Parameter )
498 | {
499 | NTSTATUS Status;
500 | PSESSION Session;
501 | PWORKER_THREAD_CTX Tctx;
502 | PuCONINFO ConInfo;
503 | PuCON_CTX Ctx;
504 | PLIST_ENTRY PduEnt;
505 | PPDU Pdu;
506 | FOUR_BYTE StatSN , ExpCmdSN , MaxCmdSN;
507 |
508 | Tctx = (PWORKER_THREAD_CTX)Parameter;
509 | Ctx = Tctx->Ctx;
510 | ConInfo = Ctx->ConInfo;
511 | Session = ConInfo->Session;
512 |
513 | while ( TRUE )
514 | {
515 | Status = KeWaitForSingleObject ( &Ctx->DispatchEvent ,
516 | Executive ,
517 | KernelMode ,
518 | FALSE ,
519 | NULL );
520 |
521 | KeClearEvent( &Ctx->DispatchEvent );
522 |
523 | while ( PduEnt = ExInterlockedRemoveHeadList ( &Ctx->InPDU , &Ctx->InLock ) )
524 | {
525 | Pdu = (PPDU)CONTAINING_RECORD ( PduEnt , PDU , PDUList );
526 | InitializeListHead ( &Pdu->PDUList );
527 | // Command Window
528 | REVERSE_BYTES ( &ExpCmdSN , &Pdu->Bhs->STAT_FIELDS.ExpCmdSN);
529 | REVERSE_BYTES ( &MaxCmdSN , &Pdu->Bhs->STAT_FIELDS.MaxCmdSN);
530 | TiUpdateCmdWindow (ConInfo , ExpCmdSN.AsULong , MaxCmdSN.AsULong);
531 | /*
532 | The presence of status
533 | (and of a residual count) is signaled though the S flag bit.
534 | p137
535 | */
536 | if ( Pdu->Bhs->GENERICBHS.Opcode == OP_DATA_IN && Pdu->Bhs->SCSI_DATA_IN.S ||
537 | Pdu->Bhs->GENERICBHS.Opcode != OP_DATA_IN)
538 | {
539 | REVERSE_BYTES ( &StatSN , &Pdu->Bhs->STAT_FIELDS.StatSN);
540 | TiUpdateStatSN ( ConInfo , StatSN.AsULong );
541 | }
542 |
543 | //DbgPrint("%s Opcode=0x%X\n" , __FUNCTION__ , Pdu->Bhs->GENERICBHS.Opcode );
544 | switch ( Pdu->Bhs->GENERICBHS.Opcode )
545 | {
546 | case OP_SCSI_REP:
547 | PtProcessResponse ( Pdu , ConInfo );
548 | break;
549 |
550 | case OP_DATA_IN:
551 | PtProcessDataIn ( Pdu , ConInfo );
552 | break;
553 |
554 | case OP_R2T:
555 | PtProcessR2T ( Pdu , ConInfo );
556 | break;
557 |
558 | case OP_SCSI_TASK_REP:
559 | PtProcessTask ( Pdu , ConInfo );
560 | break;
561 |
562 | case OP_TXT_REP:
563 | PtProcessText ( Pdu , ConInfo);
564 | break;
565 |
566 | case OP_ASYNC_MSG:
567 | PtProcessAsyncMsg (Pdu , ConInfo);
568 | break;
569 |
570 | case OP_LOGIN_REP:
571 | PtProcessLogin( Pdu , ConInfo);
572 | break;
573 |
574 | case OP_LOGOUT_REP:
575 | PtProcessLogout ( Pdu , ConInfo );
576 | break;
577 |
578 | case OP_REJECT:
579 | PtProcessReject ( Pdu , ConInfo );
580 | break;
581 |
582 | case OP_NOP_IN:
583 | PtProcessNopIn ( Pdu , ConInfo );
584 | break;
585 |
586 | default:
587 | //PtProcessError ( Pdu , ConInfo );
588 | break;
589 | }
590 | }
591 | }
592 |
593 | KdPrintEx((DPFLTR_USCSI,DBG_TRANSPORT,"Dispatcher(0x%x) Exited\n" , Tctx->No));
594 | ExFreePoolWithTag( Tctx , USCSI_TAG);
595 | //Ctx->WorkItemFlags |= CONCTX_INWORKER_SAFE;
596 | }
--------------------------------------------------------------------------------
/uSCSIPort/Transport.h:
--------------------------------------------------------------------------------
1 | #ifndef _TRANSPORT_H
2 | #define _TRANSPORT_H
3 |
4 | //
5 | // An iSCSI Session
6 | //
7 |
8 | typedef struct _SESSION
9 | {
10 | LIST_ENTRY List;
11 | //
12 | // iSCSI Command Sequence
13 | //
14 | ULONG CmdSN;
15 | //
16 | // Outstanding R2T Counter
17 | //
18 | ULONG R2TCount;
19 | //
20 | // Command Window
21 | //
22 | ULONG ExpCmdSN;
23 | ULONG MaxCmdSN;
24 | KSPIN_LOCK WindowLock;
25 | KEVENT WindowEvent;
26 |
27 | ULONG TaskTag;
28 |
29 | UCHAR ISID[6];
30 | UCHAR TSIH[2];
31 | //
32 | BOOLEAN NormalSession;
33 | //
34 | // CID Counter
35 | //
36 | USHORT CID;
37 | //
38 | // Session State
39 | //
40 | UCHAR State;
41 | //
42 | // Target
43 | //
44 | PITGT Tgt;
45 | //
46 | // Session Connections
47 | //
48 | KSPIN_LOCK ConLock;
49 | LIST_ENTRY Connections;
50 | PuCONINFO LeadingCon;
51 | PuCONINFO BestCon;
52 | //
53 | // Pdu Release Thread
54 | //
55 | LIST_ENTRY PduRelease;
56 | HANDLE PduReleaser;
57 | KEVENT PduReleaseEvent;
58 | KSPIN_LOCK PduReleaseLock;
59 | //
60 | //
61 | //
62 | HANDLE TdiPnP;
63 | //
64 | //
65 | //
66 | USCSI_CALL_BACK CallBack;
67 | //
68 | // For traffic stats
69 | //
70 | ULONG Ns100Unit;
71 | //
72 | // Session Wide Parameters
73 | //
74 | PKEY_VALUE Parameter[KEY_MaxSessionKey];
75 | }SESSION , *PSESSION;
76 |
77 | // Session States
78 |
79 | #define SESSION_STAT_FREE 0x01
80 | #define SESSION_STAT_LOGGED_IN 0x03
81 | #define SESSION_STAT_FAILED 0x04
82 |
83 | // Connection
84 | #define CTX_MAX_DISPATCH_WORKERS 1
85 | #define CTX_MAX_SEND_WORKERS 1
86 | #define CTX_MAX_R2T_WORKERS 1
87 | #define CTX_MAX_DATAIN_WORKERS 1
88 | #define CTX_MAX_PENDING_CMD_WORKERS 1
89 |
90 | typedef struct _uCON_CTX
91 | {
92 | //
93 | // in PDU queue
94 | //
95 | LIST_ENTRY InPDU;
96 | KSPIN_LOCK InLock;
97 | KEVENT DispatchEvent;
98 | HANDLE Dispatchers[CTX_MAX_DISPATCH_WORKERS];
99 | ULONG DispatcherCount;
100 | //
101 | // out PDU queue
102 | //
103 | LIST_ENTRY OutPDU;
104 | KSPIN_LOCK OutLock;
105 | KEVENT OutEvent;
106 | HANDLE Senders[CTX_MAX_SEND_WORKERS];
107 | ULONG SenderCount;
108 | //
109 | // Outstanding R2Ts
110 | //
111 | LIST_ENTRY R2Ts;
112 | KSPIN_LOCK R2TLock;
113 | KEVENT R2TEvent;
114 | HANDLE R2TWorkers[CTX_MAX_R2T_WORKERS];
115 | ULONG R2TWorkerCount;
116 | //
117 | // Incoming Data-In
118 | //
119 | LIST_ENTRY DataIns;
120 | KSPIN_LOCK DataInLock;
121 | KEVENT DataInEvent;
122 | HANDLE DataInWorkers[CTX_MAX_DATAIN_WORKERS];
123 | ULONG DataInWorkerCount;
124 | //
125 | // Command that has been acked
126 | //
127 | LIST_ENTRY PendingCompleteCmds;
128 | KSPIN_LOCK PendingCompleteCmdLock;
129 | KEVENT PendingCompleteCmdEvent;
130 | HANDLE PendingCompleteCmdWorkers[CTX_MAX_PENDING_CMD_WORKERS];
131 | ULONG PendingCompleteCmdCount;
132 | //
133 | // Pools
134 | //
135 | NPAGED_LOOKASIDE_LIST PDULookAside;
136 | NPAGED_LOOKASIDE_LIST BHSLookAside;
137 | //
138 | // For PDU assembling
139 | //
140 | PPDU PendingPDU;
141 | //
142 | // Outstanding Continue PDU
143 | //
144 | PPDU LinkPDU;
145 | //
146 | // Performance Counter
147 | //
148 | ULONG FailedIrpAllocation;
149 | //
150 | // back to
151 | //
152 | PuCONINFO ConInfo;
153 | }uCON_CTX , *PuCON_CTX;
154 |
155 | //
156 | // Worker context
157 | //
158 |
159 | typedef struct _WORKER_THREAD_CTX
160 | {
161 | PuCON_CTX Ctx;
162 | UCHAR No;
163 | }WORKER_THREAD_CTX , *PWORKER_THREAD_CTX;
164 |
165 | #define WI_PDU_IN 0x01
166 | #define WI_PDU_OUT 0x02
167 | #define WI_R2T 0x03
168 | #define WI_DATAIN 0x04
169 | #define WI_PENDING_COMPLETE_CMD 0x05
170 | #define WI_PDU_RELEASE 0x06
171 |
172 | //
173 | // Traffic stats
174 | //
175 |
176 | typedef enum _CON_STATS
177 | {
178 | CON_STATS_MIN = 0,
179 | CON_STATS_MAX,
180 | CON_STATS_AVG,
181 | CON_STATS_TIMEOUT,
182 |
183 | CON_STATS_LAST
184 | }CON_STATS;
185 |
186 | #define PENDING_TASK_HASH_SIZE 0x100
187 |
188 | //
189 | // iSCSI connection
190 | //
191 |
192 | typedef struct _uCONINFO
193 | {
194 | //
195 | // On Session list
196 | //
197 | LIST_ENTRY ConList;
198 | //
199 | // Status Numbering
200 | //
201 | ULONG ExpStatSN;
202 | //
203 | // TRUE if ExpStatSN has been initied with first StatSN
204 | //
205 | BOOLEAN ExpStatSNInited;
206 | //
207 | // StatSN Queue sorted by StatSN
208 | //
209 | SINGLE_LIST_ENTRY StatSN;
210 | //
211 | //
212 | //
213 | NPAGED_LOOKASIDE_LIST SNLookAside;
214 | //
215 | // Connection State
216 | //
217 | UCHAR State;
218 | //
219 | // ID
220 | //
221 | USHORT CID;
222 |
223 | ULONG DupResponseCount;
224 | ULONG DupStatSN;
225 | //
226 | // Transport address , endpoint , control channel
227 | //
228 | HANDLE Addr , Ep , Ctl;
229 | PFILE_OBJECT AddrObj , ConEpObj , CtlObj;
230 | //
231 | // Context
232 | //
233 | PuCON_CTX ConCtx;
234 | //
235 | // Session belonging
236 | //
237 | PSESSION Session;
238 | //
239 | // State of Text Conversation
240 | //
241 | UCHAR TextState;
242 | //
243 | // State of Login Conversation
244 | //
245 | UCHAR LoginState;
246 | UCHAR SkipOperationalNegotiation:1;
247 | UCHAR SSG:2;
248 | UCHAR CSG:2;
249 | UCHAR NSG:2;
250 | KEVENT LoginEvent;
251 | //
252 | // For Login and Text
253 | //
254 | BOOLEAN MoreWorks;
255 | PPDU Answer;
256 | //
257 | // Used by
258 | // 1. Login/Text to hold the head of a logical PDU
259 | // 2. and Data-In to hold the head of a data sequence
260 | //
261 | PPDU Logical;
262 | //
263 | //
264 | //
265 | UCHAR LogoutState;
266 | //
267 | // Hashed By InitiatorTaskTag
268 | //
269 | LIST_ENTRY PendingTasks[PENDING_TASK_HASH_SIZE];
270 | KSPIN_LOCK PendingTasksLock;
271 | //
272 | // Connection Stats
273 | //
274 | ULONG Stats[CON_STATS_LAST];
275 | //
276 | // Connection Wide Parameters
277 | //
278 | PKEY_VALUE Parameter[ KEY_LastKey - KEY_MaxSessionKey - 1];
279 | //
280 | // Transport Parameters
281 | //
282 | TDI_CONNECTION_INFO ConnectionInfo;
283 | TDI_PROVIDER_INFO ProviderInfo;
284 |
285 | }uCONINFO , *PuCONINFO;
286 |
287 | #define IsLeadingCon(c) ( (c)->Session->LeadingCon == (c) )
288 |
289 | #define KEY_CON_IDX(k) ( k - KEY_MaxSessionKey - 1 )
290 |
291 | // Text Exchange State
292 | #define TXT_STAT_IDLE 0x00
293 | #define TXT_STAT_STARTED 0x01
294 | #define TXT_STAT_PENDING_COMPLETE 0x02
295 |
296 | // Login Stages
297 | #define LOGIN_STAGE_SecurityNegotiation 0x00
298 | #define LOGIN_STAGE_LoginOperationalNegotiation 0x01
299 | #define LOGIN_STAGE_FullFeaturePhase 0x03
300 |
301 | // Login Stage State
302 | #define LOGIN_STAT_IDLE 0x00
303 | #define LOGIN_STAT_STARTED 0x01 // A new stage has started
304 | #define LOGIN_STAT_PENDING_TRANSIT 0x02 // A transit has been requested
305 |
306 | //
307 | #define CON_STAT_UNINITIALIZED 0x00
308 | #define CON_STAT_INITIALIZED 0x01
309 | #define CON_STAT_CONNECTED 0x02
310 |
311 | // RFC 3720 Connection States
312 |
313 | #define CON_STAT_FREE 0x11
314 | #define CON_STAT_XPT_WAIT 0x12
315 | #define CON_STAT_IN_LOGIN 0x14 //Login , Initialization
316 | #define CON_STAT_LOGGED_IN 0x15 //Full Feature
317 | #define CON_STAT_LOGOUT_REQED 0x16
318 | #define CON_STAT_CLEANUP_WAIT 0x17
319 |
320 | //
321 | // Protocol Data Unit
322 | //
323 | typedef struct _PDU
324 | {
325 | //
326 | // On In\Out\R2Ts\DataIns Queue or in Pending Cmd Hash
327 | //
328 | LIST_ENTRY PDUList;
329 | //
330 | // On Continue List or PendingCompleteCmds Queue
331 | //
332 | union
333 | {
334 | LIST_ENTRY Continue;
335 | LIST_ENTRY PendingCmd;
336 | };
337 | //
338 | // Referenced SCSI Cmd PDU
339 | //
340 | struct _PDU* Cmd;
341 | //
342 | //
343 | //
344 | ULONG Flags;
345 | //
346 | // Response of this command
347 | //
348 | LIST_ENTRY Resps;
349 | //
350 | // Data ins or R2Ts
351 | //
352 | LIST_ENTRY DataInOrR2T;
353 | ULONG DupDataInCount;
354 | KSPIN_LOCK DataInOrR2TLock;
355 | //
356 | // Data outs of SCSI Command / R2T
357 | //
358 | LIST_ENTRY DataOut;
359 | //
360 | // For SCSI Command and R2T
361 | // Numbering Data-Out(s) within a SCSI Command (Unsolicited Do)
362 | // or within a R2T (Solicited Do)
363 | ULONG DataSN;
364 | //
365 | // Data Offset in Data-Out buffer
366 | //
367 | ULONG DoOffset;
368 | //
369 | // SCSI staff
370 | //
371 | PIRP OrigIrp;
372 | PSCSI_REQUEST_BLOCK Srb;
373 | PUCHAR DataBuffer;
374 | //
375 | // Sending/Receiving Time of PDU
376 | //
377 | union
378 | {
379 | LARGE_INTEGER SendingTime;
380 | LARGE_INTEGER ReceivingTime;
381 | };
382 | //
383 | // SCSI_RESPONSE ExpDataSN
384 | //
385 | ULONG ExpDataSN;
386 | //
387 | // Back to
388 | //
389 | PuCON_CTX ConCtx;
390 | //
391 | PBHS Bhs;
392 | //
393 | // Buffer for both Ahs and Data
394 | //
395 | PUCHAR Buffer;
396 | PUCHAR Ahs;
397 | PUCHAR Data;
398 | // TiReceive stuffs
399 | ULONG BufferSize;
400 | ULONG Bytes;
401 | }PDU , *PPDU;
402 |
403 | #define PDU_F_DATA_IN_PROCESSED 0x00000001
404 | #define PDU_F_DATA_IN_RETRANSMIT 0x00000002
405 | #define PDU_F_CMD_CAN_COMPLETE 0x00000004
406 | //
407 | //
408 | //
409 | typedef struct _SN
410 | {
411 | SINGLE_LIST_ENTRY Next;
412 | ULONG SN;
413 | }SN , *PSN;
414 |
415 | //
416 | // Public Functions
417 | //
418 |
419 | // TransUtils.c
420 |
421 | VOID TpRegisterPnPHandlers( PSESSION Session);
422 |
423 | PPDU TpAllocatePDU(PuCON_CTX Ctx , UCHAR Opcode , UCHAR AHSLen , ULONG DataLen);
424 |
425 | VOID TpFreePDU(PuCON_CTX Ctx , PPDU Pdu ,ULONG Level);
426 |
427 | VOID TpQueuePDU(PuCON_CTX Ctx , PPDU Pdu , UCHAR Which );
428 |
429 | PuCONINFO TpBestConnection(PSESSION Session);
430 |
431 | #define TpQueueInPDU(Ctx , Pdu ) TpQueuePDU( Ctx , Pdu , WI_PDU_IN )
432 | #define TpQueueOutPDU(Ctx , Pdu ) TpQueuePDU( Ctx , Pdu , WI_PDU_OUT )
433 | #define TpQueueR2TPDU(Ctx , Pdu ) TpQueuePDU( Ctx , Pdu , WI_R2T )
434 | #define TpQueueDataInPDU(Ctx , Pdu ) TpQueuePDU( Ctx , Pdu , WI_DATAIN )
435 | #define TpQueuePendingCompleteCmd(Ctx , Pdu ) TpQueuePDU( Ctx , Pdu , WI_PENDING_COMPLETE_CMD )
436 | #define TpQueuePduRelease(Ctx , Pdu) TpQueuePDU( Ctx , Pdu , WI_PDU_RELEASE)
437 |
438 | PuCONINFO TpAddConInfo(PSESSION Session );
439 |
440 | NTSTATUS TpConnectTo( PuCONINFO Coninfo , ULONG Address , USHORT Port);
441 |
442 | PSESSION TpAllocateSession ();
443 |
444 | VOID TpFreeSession (PSESSION Session);
445 |
446 | NTSTATUS TpTest();
447 |
448 |
449 |
450 |
451 | #endif
--------------------------------------------------------------------------------
/uSCSIPort/precomp.h:
--------------------------------------------------------------------------------
1 | #ifndef PRECOMP_H
2 | #define PRECOMP_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include "uSCSIPortPublic.h"
14 | #include "uSCSIPort.h"
15 | #include "uSCSI.h"
16 | #include "Protocol.h"
17 | #include "Transport.h"
18 |
19 | #endif
20 |
--------------------------------------------------------------------------------
/uSCSIPort/uSCSI.c:
--------------------------------------------------------------------------------
1 |
2 | #include "precomp.h"
3 |
4 | NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
5 | {
6 | return STATUS_SUCCESS;
7 | }
8 |
9 | //
10 | // Global
11 | //
12 |
13 | BOOLEAN uSCSIPortInitialized = FALSE;
14 | KSPIN_LOCK SessionListLock;
15 | LIST_ENTRY SessionList;
16 |
17 | KSPIN_LOCK TgtsLock;
18 | LIST_ENTRY Targets;
19 | ULONG TgtCount;
20 |
21 | //
22 | // Exported function
23 | //
24 |
25 | ULONG TiCountTargetSize()
26 | {
27 | PITGT Itgt;
28 | ULONG Size = 0;
29 | PLIST_ENTRY TgtEnt , TgtEnt2;
30 |
31 | TgtEnt = &Targets;
32 | TgtEnt2 = TgtEnt->Flink;
33 |
34 | while ( TgtEnt2 != TgtEnt)
35 | {
36 | Itgt = CONTAINING_RECORD ( TgtEnt2 , ITGT , List );
37 | Size += strlen (Itgt->Tgt.TargetName) + 1;
38 | Size += sizeof ( TGT );
39 | TgtEnt2 = TgtEnt2->Flink;
40 | }
41 |
42 | if (!Size)
43 | return Size;
44 |
45 | return Size + sizeof (TGTS);
46 | }
47 |
48 | //
49 | //
50 | //
51 |
52 | ULONG uSCSIGetTargetsSize()
53 | {
54 | KIRQL OldIrql;
55 | ULONG Size = 0;
56 |
57 | ExAcquireSpinLock ( &TgtsLock , &OldIrql );
58 | Size = TiCountTargetSize();
59 | ExReleaseSpinLock ( &TgtsLock , OldIrql );
60 |
61 | return Size;
62 | }
63 |
64 | //
65 | //
66 | //
67 |
68 | NTSTATUS uSCSIPopTargets( PTGTS Tgts)
69 | {
70 | KIRQL OldIrql;
71 | PTGT Tgt;
72 | PITGT Itgt;
73 | PUCHAR NameBuf;
74 | ULONG Len , NameOffset;
75 | PLIST_ENTRY TgtEnt , TgtEnt2;
76 |
77 | ExAcquireSpinLock ( &TgtsLock , &OldIrql );
78 |
79 | if ( Tgts->Size != TiCountTargetSize() )
80 | return STATUS_INVALID_PARAMETER;
81 |
82 | Tgts->Count = TgtCount;
83 | Tgt = (PTGT)(Tgts + 1);
84 | NameBuf = (PUCHAR)(Tgt + Tgts->Count);
85 | NameOffset = NameBuf - (PUCHAR)Tgts;
86 |
87 | TgtEnt = &Targets;
88 | TgtEnt2 = TgtEnt->Flink;
89 |
90 | while ( TgtEnt2 != TgtEnt)
91 | {
92 | Itgt = CONTAINING_RECORD ( TgtEnt2 , ITGT , List );
93 |
94 | Len = strlen ( Itgt->Tgt.TargetName ) + 1 ;
95 |
96 | RtlCopyMemory ( NameBuf , Itgt->Tgt.TargetName , Len);
97 |
98 | Tgt->NameOffset = NameOffset;
99 | Tgt->Addr = Itgt->Tgt.Addr;
100 | Tgt->Port = Itgt->Tgt.Port;
101 |
102 | Tgt++;
103 | NameBuf += Len;
104 | NameOffset += Len;
105 |
106 | TgtEnt2 = TgtEnt2->Flink;
107 | }
108 |
109 | ExReleaseSpinLock ( &TgtsLock , OldIrql );
110 |
111 | return STATUS_SUCCESS;
112 | }
113 |
114 | //
115 | //
116 | //
117 |
118 | VOID uSCSIAddTarget(PUCHAR TgtName , ULONG Addr , USHORT Port)
119 | {
120 | ULONG Len;
121 | PITGT Itgt;
122 | KIRQL OldIrql;
123 |
124 | Len = strlen (TgtName);
125 |
126 | if ( Len )
127 | {
128 | Itgt = ExAllocatePoolWithTag ( PagedPool , sizeof (ITGT) + Len + 1, USCSI_TAG);
129 | Itgt->Tgt.TargetName = (PUCHAR)( Itgt + 1);
130 | RtlCopyMemory ( Itgt->Tgt.TargetName , TgtName , Len + 1);
131 | Itgt->Tgt.Addr =Addr;
132 | Itgt->Tgt.Port = Port;
133 |
134 | ExAcquireSpinLock ( &TgtsLock , &OldIrql );
135 | InsertTailList ( &Targets , &Itgt->List);
136 | TgtCount++;
137 | ExReleaseSpinLock ( &TgtsLock , OldIrql );
138 | }
139 | }
140 |
141 | //
142 | //
143 | //
144 |
145 | VOID uSCSIInitialize()
146 | {
147 | if ( uSCSIPortInitialized )
148 | return;
149 |
150 | PtInit();
151 | InitializeListHead ( &SessionList );
152 | InitializeListHead ( &Targets );
153 | KeInitializeSpinLock ( &SessionListLock);
154 | KeInitializeSpinLock ( &TgtsLock);
155 |
156 | uSCSIPortInitialized = TRUE;
157 | TgtCount = 0;
158 | //uSCSIAddTarget ( "iqn.com.yushang:vdisk.0001" , INETADDR (192,168,1,100) , HTONS(3260) );
159 | }
160 |
161 | //
162 | //
163 | //
164 |
165 | PVOID uSCSICreateSession( PUCHAR Target , PUSCSI_CALL_BACK CallBack )
166 | {
167 | NTSTATUS Status;
168 | PITGT Itgt;
169 | PLIST_ENTRY TgtEnt , TgtEnt2;
170 | PSESSION Session;
171 | PuCONINFO ConInfo;
172 | ULONG Cons;
173 |
174 | if (!uSCSIPortInitialized)
175 | return NULL;
176 |
177 | TgtEnt = &Targets;
178 | TgtEnt2 = TgtEnt->Flink;
179 |
180 | while ( TgtEnt != TgtEnt2 )
181 | {
182 | Itgt = CONTAINING_RECORD ( TgtEnt2 , ITGT , List);
183 | if ( !strcmp( Itgt->Tgt.TargetName , Target ))
184 | goto Found;
185 | TgtEnt2 = TgtEnt2->Flink;
186 | }
187 |
188 | return NULL;
189 |
190 | Found:
191 |
192 | if ( !CallBack->CompleteCmd )
193 | return NULL;
194 |
195 | Session = TpAllocateSession( Itgt );
196 | Session->CallBack = *CallBack;
197 |
198 | TpAddConInfo (Session);
199 |
200 | Status = PtLogin (Session->LeadingCon);
201 | if (NT_SUCCESS (Status) )
202 | {
203 | ExInterlockedInsertTailList ( &SessionList , &Session->List , &SessionListLock);
204 | return Session;
205 | }
206 | else
207 | {
208 | TpFreeSession (Session);
209 | return NULL;
210 | }
211 | }
212 |
213 | VOID PiSendDataOut(PuCON_CTX Ctx , PPDU CmdOrR2T );
214 |
215 | //
216 | //
217 | //
218 |
219 | VOID uSCSIProcessSCSICmd ( PVOID Session ,
220 | PUCHAR Cdb ,
221 | ULONG CdbLength ,
222 | PUCHAR DataBuf ,
223 | ULONG WriteSize,
224 | ULONG ReadSize ,
225 | UCHAR TaskAttr,
226 | UCHAR Dir ,
227 | PULONG Handle)
228 | {
229 | PuCONINFO ConInfo;
230 | PPDU Cmd;
231 |
232 | ConInfo = TpBestConnection (Session);
233 |
234 | Cmd = PtAssembleSCSICmd ( ConInfo ,
235 | Cdb ,
236 | CdbLength ,
237 | DataBuf ,
238 | WriteSize ,
239 | ReadSize ,
240 | TaskAttr ,
241 | Dir );
242 | if ( Handle )
243 | REVERSE_BYTES ( Handle , &Cmd->Bhs->STAT_FIELDS.InitiatorTaskTag);
244 |
245 | TpQueueOutPDU ( ConInfo->ConCtx , Cmd );
246 | PiSendDataOut ( ConInfo->ConCtx , Cmd );
247 |
248 | }
249 |
250 | //
251 | //
252 | //
253 |
254 | VOID uSCSIDiscover( ULONG Portal , USHORT Port)
255 | {
256 |
257 | }
258 |
259 | //
260 | //
261 | //
262 |
263 | PLIST_ENTRY uSCSIGetTargets()
264 | {
265 | PLIST_ENTRY Tgts = NULL;
266 |
267 | return Tgts;
268 | }
269 |
270 | //
271 | //
272 | //
273 |
274 | PLIST_ENTRY uSCSIGetSessions()
275 | {
276 | PLIST_ENTRY Sessions = NULL;
277 |
278 | return Sessions;
279 | }
280 |
281 | //
282 | //
283 | //
284 |
285 | PUSCSI_SESSION_INFO uSCSIGetSessionInfo ( PVOID Session )
286 | {
287 | PUSCSI_SESSION_INFO Info = NULL;
288 |
289 | return Info;
290 | }
291 | //
292 | // For Extension Module
293 | //
294 |
295 |
--------------------------------------------------------------------------------
/uSCSIPort/uSCSI.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef USCSI_H
3 | #define USCSI_H
4 |
5 | #define USCSI_TAG (ULONG)'uSCI'
6 |
7 | #define INETADDR(a, b, c, d) (a | (b<<8) | (c<<16) | (d<<24))
8 | #define HTONL(a) (((a&0xFF)<<24) | ((a&0xFF00)<<8) | ((a&0xFF0000)>>8) | ((a&0xFF000000)>>24))
9 | #define HTONS(a) (((0xFF&a)<<8) | ((0xFF00&a)>>8))
10 |
11 | //
12 | // debug module
13 | //
14 | //#define DBG_USCSI
15 | //#define DBG_XPT
16 | //#define DBG_PROT
17 |
18 | ULONG DbgSeq;
19 |
20 | #define TMP_Debug( c )
21 | /*
22 | #define TMP_Debug( c ) \
23 | { \
24 | DbgPrint("%08X ",DbgSeq++); \
25 | DbgPrint c; \
26 | }*/
27 |
28 | #ifdef DBG_USCSI
29 | #define USCSI_Debug( c ) \
30 | DbgPrint c
31 | #else
32 | #define USCSI_Debug( c )
33 | #endif
34 |
35 | #ifdef DBG_XPT
36 | #define XPT_Debug( c ) \
37 | DbgPrint c
38 | #else
39 | #define XPT_Debug( c )
40 | #endif
41 |
42 | #ifdef DBG_PROT
43 | #define PROT_Debug( c ) \
44 | DbgPrint c
45 | #else
46 | #define PROT_Debug( c )
47 | #endif
48 |
49 | #define DPFLTR_USCSI DPFLTR_IHVDRIVER_ID
50 |
51 | #define DBG_TRANSPORT 0x4
52 | #define DBG_TDI 0x5
53 | #define DBG_PROTOCOL 0x6
54 |
55 | typedef struct _ITGT
56 | {
57 | LIST_ENTRY List;
58 | TGT Tgt;
59 | }ITGT , *PITGT;
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/uSCSIPort/uSCSIPort.def:
--------------------------------------------------------------------------------
1 | LIBRARY uSCSIPort.sys
2 | EXPORTS
3 | uSCSIInitialize @1
4 | uSCSICreateSession @2
5 | uSCSIProcessSCSICmd @3
6 | uSCSIAddTarget @4
7 | uSCSIGetTargetsSize @5
8 | uSCSIPopTargets @6
--------------------------------------------------------------------------------
/uSCSIPort/uSCSIPort.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef _USCSI_PORT_H
3 | #define _USCSI_PORT_H
4 |
5 | #define SCSI_TASK_UNTAGGED 0x00
6 | #define SCSI_TASK_SIMPLE 0x01
7 | #define SCSI_TASK_ORDERED 0x02
8 | #define SCSI_TASK_HOQ 0x03
9 | #define SCSI_TASK_ACA 0x04
10 |
11 | // OP_SCSI_CMD direction
12 | #define SCSI_CMD_DIR_READ 0x01
13 | #define SCSI_CMD_DIR_WRITE 0x02
14 | #define SCSI_CMD_DIR_BOTH 0x03
15 | #define SCSI_CMD_DIR_NONE 0x04
16 |
17 | typedef VOID (*uSCSIComplete)( ULONG Handle ,
18 | PVOID Context ,
19 | UCHAR ScsiStatus ,
20 | PUCHAR SenseData,
21 | ULONG SenseLength );
22 |
23 | typedef struct _USCSI_CALL_BACK
24 | {
25 | uSCSIComplete CompleteCmd;
26 | PVOID CompleteCtx;
27 |
28 | }USCSI_CALL_BACK , *PUSCSI_CALL_BACK;
29 |
30 | typedef struct _USCSI_SESSION_INFO
31 | {
32 | PVOID PlaceHolder;
33 | }USCSI_SESSION_INFO , *PUSCSI_SESSION_INFO;
34 |
35 | VOID uSCSIInitialize();
36 |
37 | VOID uSCSIAddTarget(PUCHAR Tgt , ULONG Addr , USHORT Port);
38 |
39 | ULONG uSCSIGetTargetsSize();
40 |
41 | NTSTATUS uSCSIPopTargets( PTGTS Tgts);
42 |
43 | PVOID uSCSICreateSession( PUCHAR Target , PUSCSI_CALL_BACK CallBack );
44 |
45 | VOID uSCSIProcessSCSICmd ( PVOID Session ,
46 | PUCHAR Cdb ,
47 | ULONG CdbLength ,
48 | PUCHAR DataBuf ,
49 | ULONG WriteSize,
50 | ULONG ReadSize ,
51 | UCHAR TaskAttr,
52 | UCHAR Dir ,
53 | PULONG Handle);
54 |
55 | #endif
--------------------------------------------------------------------------------
/uSCSIPort/uSCSIPortPublic.h:
--------------------------------------------------------------------------------
1 | #ifndef _USCSI_PORT_PUBLIC_H
2 | #define _USCSI_PORT_PUBLIC_H
3 |
4 | typedef struct _TGT
5 | {
6 | union
7 | {
8 | PUCHAR TargetName;
9 | ULONG NameOffset;
10 | };
11 | ULONG Addr;
12 | USHORT Port;
13 | }TGT , *PTGT;
14 |
15 | typedef struct _TGTS
16 | {
17 | ULONG Count;
18 | ULONG Size;
19 | }TGTS , *PTGTS;
20 |
21 |
22 | //STATUS CODE
23 | #define STATUS_USCSI_SESSION_FAILED 0xE
24 | #endif
--------------------------------------------------------------------------------
/uSCSI设计文档.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldoldman/iSCSI_drv/e118622fa43c4756038bc72a2ef4492f807a10f8/uSCSI设计文档.pdf
--------------------------------------------------------------------------------