|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991 Microsoft Corporation
4:
5: Module Name:
6:
7: class.c
8:
9: Abstract:
10:
11: SCSI class driver routines
12:
13: Author:
14:
15: Mike Glass (mglass)
16:
17: Environment:
18:
19: kernel mode only
20:
21: Notes:
22:
23:
24: Revision History:
25:
26: --*/
27:
28: #include "stddef.h"
29: #include "ntddk.h"
30: #include "scsi.h"
31: #include "class.h"
32: #include "ntddscsi.h"
33:
34: #ifdef ALLOC_PRAGMA
35: #pragma alloc_text(init, ScsiClassGetInquiryData)
36: #pragma alloc_text(init, ScsiClassGetCapabilities)
37: #endif
38:
39: #define INQUIRY_DATA_SIZE 2048
40: #define START_UNIT_TIMEOUT 30
41:
42: VOID
43: RetryRequest(
44: PDEVICE_OBJECT DeviceObject,
45: PIRP Irp,
46: PSCSI_REQUEST_BLOCK Srb,
47: BOOLEAN Associated
48: );
49:
50: VOID
51: StartUnit(
52: IN PDEVICE_OBJECT DeviceObject
53: );
54:
55: NTSTATUS
56: ClassIoCompletion(
57: IN PDEVICE_OBJECT DeviceObject,
58: IN PIRP Irp,
59: IN PVOID Context
60: );
61:
62:
63: NTSTATUS
64: ScsiClassGetCapabilities(
65: IN PDEVICE_OBJECT PortDeviceObject,
66: OUT PIO_SCSI_CAPABILITIES *PortCapabilities
67: )
68:
69: /*++
70:
71: Routine Description:
72:
73: This routine builds and sends a request to the port driver to
74: get a pointer to a structure that describes the adapter's
75: capabilities/limitations. This routine is sychronous.
76:
77: Arguments:
78:
79: PortDeviceObject - Port driver device object representing the HBA.
80:
81: PortCapabilities - Location to store pointer to capabilities structure.
82:
83: Return Value:
84:
85: Nt status indicating the results of the operation.
86:
87: Notes:
88:
89: This routine should only be called at initialization time.
90:
91: --*/
92:
93: {
94: PIRP irp;
95: IO_STATUS_BLOCK ioStatus;
96: KEVENT event;
97: NTSTATUS status;
98:
99: //
100: // Create notification event object to be used to signal the
101: // request completion.
102: //
103:
104: KeInitializeEvent(&event, NotificationEvent, FALSE);
105:
106: //
107: // Build the synchronous request to be sent to the port driver
108: // to perform the request.
109: //
110:
111: irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
112: PortDeviceObject,
113: NULL,
114: 0,
115: PortCapabilities,
116: sizeof(PVOID),
117: FALSE,
118: &event,
119: &ioStatus);
120:
121: if (irp == NULL) {
122: return STATUS_INSUFFICIENT_RESOURCES;
123: }
124:
125: //
126: // Pass request to port driver and wait for request to complete.
127: //
128:
129: status = IoCallDriver(PortDeviceObject, irp);
130:
131: if (status == STATUS_PENDING) {
132: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
133: return(ioStatus.Status);
134: }
135:
136: return status;
137:
138: } // end ScsiClassGetCapabilities()
139:
140:
141: NTSTATUS
142: ScsiClassGetInquiryData(
143: IN PDEVICE_OBJECT PortDeviceObject,
144: OUT PSCSI_ADAPTER_BUS_INFO *ConfigInfo
145: )
146:
147: /*++
148:
149: Routine Description:
150:
151: This routine sends a request to a port driver to return
152: configuration information. Space for the information is
153: allocated by this routine. The caller is responsible for
154: freeing the configuration information. This routine is
155: synchronous.
156:
157: Arguments:
158:
159: PortDeviceObject - Port driver device object representing the HBA.
160:
161: ConfigInfo - Returns a pointer to the configuration information.
162:
163: Return Value:
164:
165: Nt status indicating the results of the operation.
166:
167: Notes:
168:
169: This routine should be called only at initialization time.
170:
171: --*/
172:
173: {
174: PIRP irp;
175: IO_STATUS_BLOCK ioStatus;
176: KEVENT event;
177: NTSTATUS status;
178: PSCSI_ADAPTER_BUS_INFO buffer;
179:
180: buffer = ExAllocatePool(PagedPool, INQUIRY_DATA_SIZE);
181: *ConfigInfo = buffer;
182:
183: if (buffer == NULL) {
184: return(STATUS_INSUFFICIENT_RESOURCES);
185: }
186:
187: //
188: // Create notification event object to be used to signal the inquiry
189: // request completion.
190: //
191:
192: KeInitializeEvent(&event, NotificationEvent, FALSE);
193:
194: //
195: // Build the synchronous request to be sent to the port driver
196: // to perform the inquiries.
197: //
198:
199: irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
200: PortDeviceObject,
201: NULL,
202: 0,
203: buffer,
204: INQUIRY_DATA_SIZE,
205: FALSE,
206: &event,
207: &ioStatus);
208:
209: if (irp == NULL) {
210: return(STATUS_INSUFFICIENT_RESOURCES);
211: }
212:
213: //
214: // Pass request to port driver and wait for request to complete.
215: //
216:
217: status = IoCallDriver(PortDeviceObject, irp);
218:
219: if (status == STATUS_PENDING) {
220: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
221: status = ioStatus.Status;
222: }
223:
224: if (!NT_SUCCESS(status)) {
225:
226: //
227: // Free the buffer on an error.
228: //
229:
230: ExFreePool(buffer);
231: *ConfigInfo = NULL;
232:
233: }
234:
235: return status;
236:
237: } // end ScsiClassGetInquiryData()
238:
239:
240: NTSTATUS
241: ScsiClassReadDriveCapacity(
242: IN PDEVICE_OBJECT DeviceObject
243: )
244:
245: /*++
246:
247: Routine Description:
248:
249: This routine sends a READ CAPACITY to the requested device, updates
250: the geometry information in the device object and returns
251: when it is complete. This routine is synchronous.
252:
253: Arguments:
254:
255: DeviceObject - Supplies a pointer to the device object that represents
256: the device whose capacity is to be read.
257:
258: Return Value:
259:
260: Status is returned.
261:
262: --*/
263: {
264: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
265: PCDB cdb;
266: PREAD_CAPACITY_DATA readCapacityBuffer;
267: SCSI_REQUEST_BLOCK srb;
268: ULONG lastSector;
269: ULONG retries = 1;
270: NTSTATUS status;
271:
272: //
273: // Allocate read capacity buffer from nonpaged pool.
274: //
275:
276: readCapacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
277: sizeof(READ_CAPACITY_DATA));
278:
279: if (!readCapacityBuffer) {
280: return(STATUS_INSUFFICIENT_RESOURCES);
281: }
282:
283: RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
284:
285: //
286: // Build the read capacity CDB.
287: //
288:
289: srb.CdbLength = 10;
290: cdb = (PCDB)srb.Cdb;
291:
292: //
293: // Set timeout value from device extension.
294: //
295:
296: srb.TimeOutValue = deviceExtension->TimeOutValue;
297:
298: cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
299:
300: Retry:
301:
302: status = ScsiClassSendSrbSynchronous(DeviceObject,
303: &srb,
304: readCapacityBuffer,
305: sizeof(READ_CAPACITY_DATA),
306: FALSE);
307:
308: if (NT_SUCCESS(status)) {
309:
310: //
311: // Copy sector size from read capacity buffer to device extension
312: // in reverse byte order.
313: //
314:
315: deviceExtension->DiskGeometry->BytesPerSector = 0;
316:
317: ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte0 =
318: ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte3;
319:
320: ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte1 =
321: ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte2;
322:
323: //
324: // Copy last sector in reverse byte order.
325: //
326:
327: ((PFOUR_BYTE)&lastSector)->Byte0 =
328: ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte3;
329:
330: ((PFOUR_BYTE)&lastSector)->Byte1 =
331: ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte2;
332:
333: ((PFOUR_BYTE)&lastSector)->Byte2 =
334: ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte1;
335:
336: ((PFOUR_BYTE)&lastSector)->Byte3 =
337: ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte0;
338:
339: //
340: // Calculate sector to byte shift.
341: //
342:
343: WHICH_BIT(deviceExtension->DiskGeometry->BytesPerSector, deviceExtension->SectorShift);
344:
345: DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
346: deviceExtension->DiskGeometry->BytesPerSector));
347:
348: DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
349: lastSector + 1));
350:
351: //
352: // Calculate media capacity in bytes.
353: //
354:
355: deviceExtension->PartitionLength =
356: LiFromLong(lastSector + 1);
357:
358: //
359: // Calculate number of cylinders.
360: //
361:
362: deviceExtension->DiskGeometry->Cylinders =
363: LiFromLong((lastSector + 1)/(32 * 64));
364:
365: deviceExtension->PartitionLength =
366: LiShl(deviceExtension->PartitionLength,
367: deviceExtension->SectorShift);
368:
369: if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
370:
371: //
372: // This device supports removable media.
373: //
374:
375: deviceExtension->DiskGeometry->MediaType = RemovableMedia;
376:
377: } else {
378:
379: //
380: // Assume media type is fixed disk.
381: //
382:
383: deviceExtension->DiskGeometry->MediaType = FixedMedia;
384: }
385:
386: //
387: // Assume sectors per track are 32;
388: //
389:
390: deviceExtension->DiskGeometry->SectorsPerTrack = 32;
391:
392: //
393: // Assume tracks per cylinder (number of heads) is 64.
394: //
395:
396: deviceExtension->DiskGeometry->TracksPerCylinder = 64;
397: }
398:
399: if (status == STATUS_VERIFY_REQUIRED) {
400:
401: //
402: // Routine ScsiClassSendSrbSynchronous does not retry
403: // requests returned with this status.
404: // Read Capacities should be retried
405: // anyway.
406: //
407:
408: if (retries--) {
409:
410: //
411: // Retry request.
412: //
413:
414: goto Retry;
415: }
416: }
417:
418: if (!NT_SUCCESS(status)) {
419:
420: //
421: // If the read capacity fails, set the geometry to reasonable parameter
422: // so things don't fail at unexpected places. Zero the geometry
423: // except for the bytes per sector and sector shift.
424: //
425:
426: RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY));
427:
428: deviceExtension->DiskGeometry->BytesPerSector = 512;
429:
430: deviceExtension->SectorShift = 9;
431:
432: deviceExtension->PartitionLength = LiFromUlong(0);
433:
434: if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
435:
436: //
437: // This device supports removable media.
438: //
439:
440: deviceExtension->DiskGeometry->MediaType = RemovableMedia;
441:
442: } else {
443:
444: //
445: // Assume media type is fixed disk.
446: //
447:
448: deviceExtension->DiskGeometry->MediaType = FixedMedia;
449: }
450: }
451:
452: //
453: // Deallocate read capacity buffer.
454: //
455:
456: ExFreePool(readCapacityBuffer);
457:
458: return status;
459:
460: } // end ScsiClassReadDriveCapacity()
461:
462:
463: VOID
464: ScsiClassReleaseQueue(
465: IN PDEVICE_OBJECT DeviceObject
466: )
467:
468: /*++
469:
470: Routine Description:
471:
472: This routine issues an internal device control command
473: to the port driver to release a frozen queue. The call
474: is issued asynchronously as ScsiClassReleaseQueue will be invoked
475: from the IO completion DPC (and will have no context to
476: wait for a synchronous call to complete).
477:
478: Arguments:
479:
480: DeviceObject - The device object for the logical unit with
481: the frozen queue.
482:
483: Return Value:
484:
485: None.
486:
487: --*/
488: {
489: PIO_STACK_LOCATION irpStack;
490: PIRP irp;
491: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
492: PCOMPLETION_CONTEXT context;
493: PSCSI_REQUEST_BLOCK srb;
494:
495: //
496: // Allocate context from nonpaged pool.
497: //
498:
499: context = ExAllocatePool(NonPagedPoolMustSucceed,
500: sizeof(COMPLETION_CONTEXT));
501:
502: //
503: // Save the device object in the context for use by the completion
504: // routine.
505: //
506:
507: context->DeviceObject = DeviceObject;
508: srb = &context->Srb;
509:
510: //
511: // Zero out srb.
512: //
513:
514: RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
515:
516: //
517: // Write length to SRB.
518: //
519:
520: srb->Length = SCSI_REQUEST_BLOCK_SIZE;
521:
522: //
523: // Set up SCSI bus address.
524: //
525:
526: srb->PathId = deviceExtension->PathId;
527: srb->TargetId = deviceExtension->TargetId;
528: srb->Lun = deviceExtension->Lun;
529:
530: //
531: // If this device is removable then flush the queue. This will also
532: // release it.
533: //
534:
535: if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
536:
537: srb->Function = SRB_FUNCTION_FLUSH_QUEUE;
538:
539: } else {
540:
541: srb->Function = SRB_FUNCTION_RELEASE_QUEUE;
542:
543: }
544:
545: //
546: // Build the asynchronous request to be sent to the port driver.
547: //
548:
549: irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
550:
551: IoSetCompletionRoutine(irp,
552: (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
553: context,
554: TRUE,
555: TRUE,
556: TRUE);
557:
558: irpStack = IoGetNextIrpStackLocation(irp);
559:
560: irpStack->MajorFunction = IRP_MJ_SCSI;
561:
562: srb->OriginalRequest = irp;
563:
564: //
565: // Store the SRB address in next stack for port driver.
566: //
567:
568: irpStack->Parameters.Scsi.Srb = srb;
569:
570: IoCallDriver(deviceExtension->PortDeviceObject, irp);
571:
572: return;
573:
574: } // end ScsiClassReleaseQueue()
575:
576:
577: VOID
578: StartUnit(
579: IN PDEVICE_OBJECT DeviceObject
580: )
581:
582: /*++
583:
584: Routine Description:
585:
586: Send command to SCSI unit to start or power up.
587: Because this command is issued asynchronounsly, that is, without
588: waiting on it to complete, the IMMEDIATE flag is not set. This
589: means that the CDB will not return until the drive has powered up.
590: This should keep subsequent requests from being submitted to the
591: device before it has completely spun up.
592: This routine is called from the InterpretSense routine, when a
593: request sense returns data indicating that a drive must be
594: powered up.
595:
596: Arguments:
597:
598: DeviceObject - The device object for the logical unit with
599: the frozen queue.
600:
601: Return Value:
602:
603: None.
604:
605: --*/
606: {
607: PIO_STACK_LOCATION irpStack;
608: PIRP irp;
609: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
610: PSCSI_REQUEST_BLOCK srb;
611: PCOMPLETION_CONTEXT context;
612: PCDB cdb;
613:
614: //
615: // Allocate Srb from nonpaged pool.
616: //
617:
618: context = ExAllocatePool(NonPagedPoolMustSucceed,
619: sizeof(COMPLETION_CONTEXT));
620:
621: //
622: // Save the device object in the context for use by the completion
623: // routine.
624: //
625:
626: context->DeviceObject = DeviceObject;
627: srb = &context->Srb;
628:
629: //
630: // Zero out srb.
631: //
632:
633: RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
634:
635: //
636: // Write length to SRB.
637: //
638:
639: srb->Length = SCSI_REQUEST_BLOCK_SIZE;
640:
641: //
642: // Set up SCSI bus address.
643: //
644:
645: srb->PathId = deviceExtension->PathId;
646: srb->TargetId = deviceExtension->TargetId;
647: srb->Lun = deviceExtension->Lun;
648:
649: srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
650:
651: //
652: // Set timeout value large enough for drive to spin up.
653: //
654:
655: srb->TimeOutValue = START_UNIT_TIMEOUT;
656:
657: //
658: // Set the transfer length.
659: //
660:
661: srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
662:
663: //
664: // Build the start unit CDB.
665: //
666:
667: srb->CdbLength = 6;
668: cdb = (PCDB)srb->Cdb;
669:
670: cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
671: cdb->START_STOP.Start = 1;
672: cdb->START_STOP.LogicalUnitNumber = srb->Lun;
673:
674: //
675: // Build the asynchronous request to be sent to the port driver.
676: // Since this routine is called from a DPC the IRP should always be
677: // available.
678: //
679:
680: irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
681:
682: IoSetCompletionRoutine(irp,
683: (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
684: context,
685: TRUE,
686: TRUE,
687: TRUE);
688:
689: irpStack = IoGetNextIrpStackLocation(irp);
690:
691: irpStack->MajorFunction = IRP_MJ_SCSI;
692:
693: srb->OriginalRequest = irp;
694:
695: //
696: // Store the SRB address in next stack for port driver.
697: //
698:
699: irpStack->Parameters.Scsi.Srb = srb;
700:
701: //
702: // Call the port driver with the IRP.
703: //
704:
705: IoCallDriver(deviceExtension->PortDeviceObject, irp);
706:
707: return;
708:
709: } // end StartUnit()
710:
711:
712: NTSTATUS
713: ScsiClassAsynchronousCompletion(
714: PDEVICE_OBJECT DeviceObject,
715: PIRP Irp,
716: PVOID Context
717: )
718: /*++
719:
720: Routine Description:
721:
722: This routine is called when an asynchronous I/O request
723: which was issused by the class driver completes. Examples of such requests
724: are release queue or START UNIT. This routine releases the queue if
725: necessary. It then frees the context and the IRP.
726:
727: Arguments:
728:
729: DeviceObject - The device object for the logical unit; however since this
730: is the top stack location the value is NULL.
731:
732: Irp - Supplies a pointer to the Irp to be processed.
733:
734: Context - Supplies the context to be used to process this request.
735:
736: Return Value:
737:
738: None.
739:
740: --*/
741:
742: {
743: PCOMPLETION_CONTEXT context = Context;
744: PSCSI_REQUEST_BLOCK srb;
745:
746: srb = &context->Srb;
747:
748: //
749: // If this is an execute srb, then check the return status and make sure.
750: // the queue is not frozen.
751: //
752:
753: if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
754:
755: //
756: // Check for a frozen queue.
757: //
758:
759: if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
760:
761: //
762: // Unfreeze the queue getting the device object from the context.
763: //
764:
765: ScsiClassReleaseQueue(context->DeviceObject);
766: }
767: }
768:
769: //
770: // Free the context and the Irp.
771: //
772:
773: if (Irp->MdlAddress != NULL) {
774: MmUnlockPages(Irp->MdlAddress);
775: IoFreeMdl(Irp->MdlAddress);
776:
777: Irp->MdlAddress = NULL;
778: }
779:
780: ExFreePool(context);
781: IoFreeIrp(Irp);
782:
783: //
784: // Indicate the I/O system should stop processing the Irp completion.
785: //
786:
787: return STATUS_MORE_PROCESSING_REQUIRED;
788:
789: } // ScsiClassAsynchronousCompletion()
790:
791:
792: VOID
793: ScsiClassSplitRequest(
794: IN PDEVICE_OBJECT DeviceObject,
795: IN PIRP Irp,
796: IN ULONG MaximumBytes
797: )
798:
799: /*++
800:
801: Routine Description:
802:
803: Break request into smaller requests. Each new request will be the
804: maximum transfer size that the port driver can handle or if it
805: is the final request, it may be the residual size.
806:
807: The number of IRPs required to process this request is written in the
808: current stack of the original IRP. Then as each new IRP completes
809: the count in the original IRP is decremented. When the count goes to
810: zero, the original IRP is completed.
811:
812: Arguments:
813:
814: DeviceObject - Pointer to the class device object to be addressed.
815:
816: Irp - Pointer to Irp the orginal request.
817:
818: Return Value:
819:
820: None.
821:
822: --*/
823:
824: {
825: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
826: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
827: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
828: ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
829: LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
830: PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
831: ULONG dataLength = MaximumBytes;
832: ULONG irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes;
833: PSCSI_REQUEST_BLOCK srb;
834: ULONG i;
835:
836: DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount));
837: DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp));
838:
839: //
840: // If all partial transfers complete successfully then the status and
841: // bytes transferred are already set up. Failing a partial-transfer IRP
842: // will set status to error and bytes transferred to 0 during
843: // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
844: // asynchronous partial transfers. This is an optimization for the
845: // successful case.
846: //
847:
848: Irp->IoStatus.Status = STATUS_SUCCESS;
849: Irp->IoStatus.Information = transferByteCount;
850:
851: //
852: // Save number of IRPs to complete count on current stack
853: // of original IRP.
854: //
855:
856: nextIrpStack->Parameters.Others.Argument1 = (PVOID) irpCount;
857:
858: for (i = 0; i < irpCount; i++) {
859:
860: PIRP newIrp;
861: PIO_STACK_LOCATION newIrpStack;
862:
863: //
864: // Allocate new IRP.
865: //
866:
867: newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
868:
869: if (newIrp == NULL) {
870:
871: DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
872:
873: //
874: // If an Irp can't be allocated then the orginal request cannot
875: // be executed. If this is the first request then just fail the
876: // orginal request; otherwise just return. When the pending
877: // requests complete, they will complete the original request.
878: // In either case set the IRP status to failure.
879: //
880:
881: Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
882: Irp->IoStatus.Information = 0;
883:
884: if (i == 0) {
885: IoCompleteRequest(Irp, IO_NO_INCREMENT);
886: }
887:
888: return;
889: }
890:
891: DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp));
892:
893: //
894: // Write MDL address to new IRP. In the port driver the SRB data
895: // buffer field is used as an offset into the MDL, so the same MDL
896: // can be used for each partial transfer. This saves having to build
897: // a new MDL for each partial transfer.
898: //
899:
900: newIrp->MdlAddress = Irp->MdlAddress;
901:
902: //
903: // At this point there is no current stack. IoSetNextIrpStackLocation
904: // will make the first stack location the current stack so that the
905: // SRB address can be written there.
906: //
907:
908: IoSetNextIrpStackLocation(newIrp);
909: newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
910:
911: newIrpStack->MajorFunction = currentIrpStack->MajorFunction;
912: newIrpStack->Parameters.Read.Length = dataLength;
913: newIrpStack->Parameters.Read.ByteOffset = startingOffset;
914: newIrpStack->DeviceObject = DeviceObject;
915:
916: //
917: // Build SRB and CDB.
918: //
919:
920: ScsiClassBuildRequest(DeviceObject, newIrp);
921:
922: //
923: // Adjust SRB for this partial transfer.
924: //
925:
926: newIrpStack = IoGetNextIrpStackLocation(newIrp);
927:
928: srb = newIrpStack->Parameters.Others.Argument1;
929: srb->DataBuffer = dataBuffer;
930:
931: //
932: // Write original IRP address to new IRP.
933: //
934:
935: newIrp->AssociatedIrp.MasterIrp = Irp;
936:
937: //
938: // Set the completion routine to ScsiClassIoCompleteAssociated.
939: //
940:
941: IoSetCompletionRoutine(newIrp,
942: ScsiClassIoCompleteAssociated,
943: srb,
944: TRUE,
945: TRUE,
946: TRUE);
947:
948: //
949: // Call port driver with new request.
950: //
951:
952: IoCallDriver(deviceExtension->PortDeviceObject, newIrp);
953:
954: //
955: // Set up for next request.
956: //
957:
958: dataBuffer = (PCHAR)dataBuffer + MaximumBytes;
959:
960: transferByteCount -= MaximumBytes;
961:
962: if (transferByteCount > MaximumBytes) {
963:
964: dataLength = MaximumBytes;
965:
966: } else {
967:
968: dataLength = transferByteCount;
969: }
970:
971: //
972: // Adjust disk byte offset.
973: //
974:
975: startingOffset = LiAdd(startingOffset, LiFromUlong(MaximumBytes));
976: }
977:
978: return;
979:
980: } // end ScsiClassSplitRequest()
981:
982:
983: NTSTATUS
984: ScsiClassIoComplete(
985: IN PDEVICE_OBJECT DeviceObject,
986: IN PIRP Irp,
987: IN PVOID Context
988: )
989:
990: /*++
991:
992: Routine Description:
993:
994: This routine executes when the port driver has completed a request.
995: It looks at the SRB status in the completing SRB and if not success
996: it checks for valid request sense buffer information. If valid, the
997: info is used to update status with more precise message of type of
998: error. This routine deallocates the SRB.
999:
1000: Arguments:
1001:
1002: DeviceObject - Supplies the device object which represents the logical
1003: unit.
1004:
1005: Irp - Supplies the Irp which has completed.
1006:
1007: Context - Supplies a pointer to the SRB.
1008:
1009: Return Value:
1010:
1011: NT status
1012:
1013: --*/
1014:
1015: {
1016: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1017: PSCSI_REQUEST_BLOCK srb = Context;
1018: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1019: NTSTATUS status;
1020: BOOLEAN retry;
1021:
1022: //
1023: // Check SRB status for success of completing request.
1024: //
1025:
1026: if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
1027:
1028: DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx", Irp, srb));
1029:
1030: //
1031: // Release the queue if it is frozen.
1032: //
1033:
1034: if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
1035: ScsiClassReleaseQueue(DeviceObject);
1036: }
1037:
1038: retry = ScsiClassInterpretSenseInfo(
1039: DeviceObject,
1040: srb,
1041: irpStack->MajorFunction,
1042: irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
1043: MAXIMUM_RETRIES - ((ULONG)irpStack->Parameters.Others.Argument4),
1044: &status);
1045:
1046: //
1047: // If the status is verified required and the this request
1048: // should bypass verify required then retry the request.
1049: //
1050:
1051: if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
1052: status == STATUS_VERIFY_REQUIRED) {
1053:
1054: status = STATUS_IO_DEVICE_ERROR;
1055: retry = TRUE;
1056:
1057: }
1058:
1059: if (retry && ((ULONG)irpStack->Parameters.Others.Argument4)--) {
1060:
1061: //
1062: // Retry request.
1063: //
1064:
1065: DebugPrint((1, "Retry request %lx\n", Irp));
1066:
1067: RetryRequest(DeviceObject, Irp, srb, FALSE);
1068:
1069: return STATUS_MORE_PROCESSING_REQUIRED;
1070: }
1071:
1072:
1073:
1074: } else {
1075:
1076: //
1077: // Set status for successful request.
1078: //
1079:
1080: status = STATUS_SUCCESS;
1081:
1082: } // end if (SRB_STATUS(srb->SrbStatus) ...
1083:
1084: //
1085: // Return SRB to nonpaged pool.
1086: //
1087:
1088: if (srb->SrbFlags & SRB_FLAGS_ALLOCATED_FROM_ZONE) {
1089:
1090: ExInterlockedFreeToZone( deviceExtension->SrbZone,
1091: srb,
1092: deviceExtension->SrbZoneSpinLock);
1093:
1094: } else {
1095:
1096: ExFreePool(srb);
1097:
1098: }
1099:
1100: //
1101: // Set status in completing IRP.
1102: //
1103:
1104: Irp->IoStatus.Status = status;
1105:
1106: //
1107: // Set the hard error if necessary.
1108: //
1109:
1110: if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
1111:
1112: //
1113: // Store DeviceObject for filesystem, and clear
1114: // in IoStatus.Information field.
1115: //
1116:
1117: IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1118: Irp->IoStatus.Information = 0;
1119:
1120: }
1121:
1122: //
1123: // If pending has be returned for this irp then mark the current stack as
1124: // pending.
1125: //
1126:
1127: if (Irp->PendingReturned) {
1128: IoMarkIrpPending(Irp);
1129: }
1130:
1131: return status;
1132:
1133: } // end ScsiClassIoComplete()
1134:
1135:
1136: NTSTATUS
1137: ScsiClassIoCompleteAssociated(
1138: IN PDEVICE_OBJECT DeviceObject,
1139: IN PIRP Irp,
1140: IN PVOID Context
1141: )
1142:
1143: /*++
1144:
1145: Routine Description:
1146:
1147: This routine executes when the port driver has completed a request.
1148: It looks at the SRB status in the completing SRB and if not success
1149: it checks for valid request sense buffer information. If valid, the
1150: info is used to update status with more precise message of type of
1151: error. This routine deallocates the SRB. This routine is used for
1152: requests which were build by split request. After it has processed
1153: the request it decrements the Irp count in the master Irp. If the
1154: count goes to zero then the master Irp is completed.
1155:
1156: Arguments:
1157:
1158: DeviceObject - Supplies the device object which represents the logical
1159: unit.
1160:
1161: Irp - Supplies the Irp which has completed.
1162:
1163: Context - Supplies a pointer to the SRB.
1164:
1165: Return Value:
1166:
1167: NT status
1168:
1169: --*/
1170:
1171: {
1172: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1173: PSCSI_REQUEST_BLOCK srb = Context;
1174: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1175: INTERLOCKED_RESULT irpCount;
1176: PIRP originalIrp = Irp->AssociatedIrp.MasterIrp;
1177: NTSTATUS status;
1178: BOOLEAN retry;
1179:
1180: //
1181: // Check SRB status for success of completing request.
1182: //
1183:
1184: if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
1185:
1186: DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp, srb));
1187:
1188: //
1189: // Release the queue if it is frozen.
1190: //
1191:
1192: if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
1193: ScsiClassReleaseQueue(DeviceObject);
1194: }
1195:
1196: retry = ScsiClassInterpretSenseInfo(
1197: DeviceObject,
1198: srb,
1199: irpStack->MajorFunction,
1200: irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
1201: MAXIMUM_RETRIES - ((ULONG)irpStack->Parameters.Others.Argument4),
1202: &status);
1203:
1204: //
1205: // If the status is verified required and the this request
1206: // should bypass verify required then retry the request.
1207: //
1208:
1209: if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
1210: status == STATUS_VERIFY_REQUIRED) {
1211:
1212: status = STATUS_IO_DEVICE_ERROR;
1213: retry = TRUE;
1214:
1215: }
1216:
1217: if (retry && ((ULONG)irpStack->Parameters.Others.Argument4)--) {
1218:
1219: //
1220: // Retry request.
1221: //
1222:
1223: DebugPrint((1, "Retry request %lx\n", Irp));
1224:
1225: RetryRequest(DeviceObject, Irp, srb, TRUE);
1226:
1227: return STATUS_MORE_PROCESSING_REQUIRED;
1228: }
1229:
1230:
1231:
1232: } else {
1233:
1234: //
1235: // Set status for successful request.
1236: //
1237:
1238: status = STATUS_SUCCESS;
1239:
1240: } // end if (SRB_STATUS(srb->SrbStatus) ...
1241:
1242: //
1243: // Return SRB to nonpaged pool.
1244: //
1245:
1246: if (srb->SrbFlags & SRB_FLAGS_ALLOCATED_FROM_ZONE) {
1247:
1248: ExInterlockedFreeToZone( deviceExtension->SrbZone,
1249: srb,
1250: deviceExtension->SrbZoneSpinLock);
1251:
1252: } else {
1253:
1254: ExFreePool(srb);
1255:
1256: }
1257:
1258:
1259: //
1260: // Set status in completing IRP.
1261: //
1262:
1263: Irp->IoStatus.Status = status;
1264:
1265: DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp));
1266:
1267: //
1268: // Get next stack location. This original request is unused
1269: // except to keep track of the completing partial IRPs so the
1270: // stack location is valid.
1271: //
1272:
1273: irpStack = IoGetNextIrpStackLocation(originalIrp);
1274:
1275: //
1276: // Update status only if error so that if any partial transfer
1277: // completes with error, then the original IRP will return with
1278: // error. If any of the asynchronous partial transfer IRPs fail,
1279: // with an error then the original IRP will return 0 bytes transfered.
1280: // This is an optimization for successful transfers.
1281: //
1282:
1283: if (!NT_SUCCESS(status)) {
1284:
1285: originalIrp->IoStatus.Status = status;
1286: originalIrp->IoStatus.Information = 0;
1287:
1288:
1289: //
1290: // Set the hard error if necessary.
1291: //
1292:
1293: if (IoIsErrorUserInduced(status)) {
1294:
1295: //
1296: // Store DeviceObject for filesystem.
1297: //
1298:
1299: IoSetHardErrorOrVerifyDevice(originalIrp, DeviceObject);
1300:
1301: }
1302:
1303: }
1304:
1305: //
1306: // Decrement and get the count of remaining IRPs.
1307: //
1308:
1309: irpCount = ExInterlockedDecrementLong(
1310: (PLONG)&irpStack->Parameters.Others.Argument1,
1311: &deviceExtension->SplitRequestSpinLock);
1312:
1313: DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
1314: irpCount));
1315:
1316: if (irpCount == ResultZero) {
1317:
1318: //
1319: // All partial IRPs have completed.
1320: //
1321:
1322: DebugPrint((2,
1323: "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
1324: originalIrp));
1325:
1326: IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
1327: }
1328:
1329: //
1330: // Deallocate IRP and indicate the I/O system should not attempt any more
1331: // processing.
1332: //
1333:
1334: IoFreeIrp(Irp);
1335:
1336: return STATUS_MORE_PROCESSING_REQUIRED;
1337:
1338: } // end ScsiClassIoCompleteAssociated()
1339:
1340:
1341: NTSTATUS
1342: ScsiClassSendSrbSynchronous(
1343: PDEVICE_OBJECT DeviceObject,
1344: PSCSI_REQUEST_BLOCK Srb,
1345: PVOID BufferAddress,
1346: ULONG BufferLength,
1347: BOOLEAN WriteToDevice
1348: )
1349:
1350: /*++
1351:
1352: Routine Description:
1353:
1354: This routine is called by SCSI device controls to complete an
1355: SRB and send it to the port driver synchronously (ie wait for
1356: completion). The CDB is already completed along with the SRB CDB
1357: size and request timeout value.
1358:
1359: Arguments:
1360:
1361: DeviceObject - Supplies the device object which represents the logical
1362: unit.
1363:
1364: Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
1365:
1366: BufferAddress - Supplies the address of the buffer.
1367:
1368: BufferLength - Supplies the length in bytes of the buffer.
1369:
1370: WriteToDevice - Indicates the data should be transfer to the device.
1371:
1372: Return Value:
1373:
1374: Nt status indicating the final results of the operation.
1375:
1376: --*/
1377:
1378: {
1379: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1380: IO_STATUS_BLOCK ioStatus;
1381: ULONG controlType;
1382: PIRP irp;
1383: PIO_STACK_LOCATION irpStack;
1384: KEVENT event;
1385: PUCHAR senseInfoBuffer;
1386: ULONG retryCount = MAXIMUM_RETRIES;
1387: NTSTATUS status;
1388: BOOLEAN retry;
1389:
1390: //
1391: // Write length to SRB.
1392: //
1393:
1394: Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1395:
1396: //
1397: // Set SCSI bus address.
1398: //
1399:
1400: Srb->PathId = deviceExtension->PathId;
1401: Srb->TargetId = deviceExtension->TargetId;
1402: Srb->Lun = deviceExtension->Lun;
1403:
1404: Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1405:
1406: //
1407: // NOTICE: The SCSI-II specification indicates that this field should be
1408: // zero; however, some target controllers ignore the logical unit number
1409: // in the INDENTIFY message and only look at the logical unit number field
1410: // in the CDB.
1411: //
1412:
1413: Srb->Cdb[1] |= deviceExtension->Lun << 5;
1414:
1415: //
1416: // Enable auto request sense.
1417: //
1418:
1419: Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1420:
1421: //
1422: // Sense buffer is in aligned nonpaged pool.
1423: //
1424:
1425: senseInfoBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
1426:
1427: if (senseInfoBuffer == NULL) {
1428:
1429: DebugPrint((1,
1430: "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
1431: return(STATUS_INSUFFICIENT_RESOURCES);
1432: }
1433:
1434: Srb->SenseInfoBuffer = senseInfoBuffer;
1435:
1436: Srb->DataBuffer = BufferAddress;
1437:
1438: //
1439: // Start retries here.
1440: //
1441:
1442: retry:
1443:
1444: //
1445: // Set the event object to the unsignaled state.
1446: // It will be used to signal request completion.
1447: //
1448:
1449: KeInitializeEvent(&event, NotificationEvent, FALSE);
1450:
1451: //
1452: // Set controlType and Srb direction flags.
1453: //
1454:
1455: if (BufferAddress != NULL) {
1456:
1457: if (WriteToDevice) {
1458:
1459: controlType = IOCTL_SCSI_EXECUTE_OUT;
1460: Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
1461:
1462: } else {
1463:
1464: controlType = IOCTL_SCSI_EXECUTE_IN;
1465: Srb->SrbFlags = SRB_FLAGS_DATA_IN;
1466:
1467: }
1468:
1469: } else {
1470:
1471: BufferLength = 0;
1472: controlType = IOCTL_SCSI_EXECUTE_NONE;
1473: Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1474: }
1475:
1476: //
1477: // Build device I/O control request with data transfer.
1478: //
1479:
1480: irp = IoBuildDeviceIoControlRequest( controlType,
1481: deviceExtension->PortDeviceObject,
1482: NULL,
1483: 0,
1484: BufferAddress,
1485: BufferLength,
1486: TRUE,
1487: &event,
1488: &ioStatus);
1489:
1490: if (irp == NULL) {
1491: ExFreePool(senseInfoBuffer);
1492: DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
1493: return(STATUS_INSUFFICIENT_RESOURCES);
1494: }
1495:
1496: //
1497: // Disable synchronous transfer for these requests.
1498: //
1499:
1500: Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1501:
1502: //
1503: // Set the transfer length.
1504: //
1505:
1506: Srb->DataTransferLength = BufferLength;
1507:
1508: //
1509: // Zero out status.
1510: //
1511:
1512: Srb->ScsiStatus = Srb->SrbStatus = 0;
1513:
1514: Srb->NextSrb = 0;
1515:
1516: //
1517: // Get next stack location.
1518: //
1519:
1520: irpStack = IoGetNextIrpStackLocation(irp);
1521:
1522: //
1523: // Set up SRB for execute scsi request. Save SRB address in next stack
1524: // for the port driver.
1525: //
1526:
1527: irpStack->Parameters.Scsi.Srb = Srb;
1528:
1529: //
1530: // Set up IRP Address.
1531: //
1532:
1533: Srb->OriginalRequest = irp;
1534:
1535: //
1536: // Call the port driver with the request and wait for it to complete.
1537: //
1538:
1539: status = IoCallDriver(deviceExtension->PortDeviceObject, irp);
1540:
1541: if (status == STATUS_PENDING) {
1542: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1543: }
1544:
1545: //
1546: // Check that request completed without error.
1547: //
1548:
1549: if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
1550:
1551: //
1552: // Release the queue if it is frozen.
1553: //
1554:
1555: if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
1556: ScsiClassReleaseQueue(DeviceObject);
1557: }
1558:
1559: //
1560: // Update status and determine if request should be retried.
1561: //
1562:
1563: retry = ScsiClassInterpretSenseInfo(DeviceObject,
1564: Srb,
1565: IRP_MJ_SCSI,
1566: 0,
1567: MAXIMUM_RETRIES - retryCount,
1568: &status);
1569:
1570: if (retry) {
1571:
1572: if ((status == STATUS_DEVICE_NOT_READY && ((PSENSE_DATA) senseInfoBuffer)
1573: ->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) ||
1574: SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) {
1575:
1576: LARGE_INTEGER delay;
1577:
1578: //
1579: // Delay for 2 seconds.
1580: //
1581:
1582: delay = LiFromLong( - 10 * 1000 * 1000 * 2 );
1583:
1584: //
1585: // Stall for a while to let the controller spinup.
1586: //
1587:
1588: KeDelayExecutionThread(KernelMode,
1589: FALSE,
1590: &delay);
1591:
1592: }
1593:
1594:
1595: //
1596: // If retries are not exhausted then retry this operation.
1597: //
1598:
1599: if (retryCount--) {
1600: goto retry;
1601: }
1602: }
1603:
1604: } else {
1605:
1606: status = STATUS_SUCCESS;
1607: }
1608:
1609: ExFreePool(senseInfoBuffer);
1610: return status;
1611:
1612: } // end ScsiClassSendSrbSynchronous()
1613:
1614:
1615: BOOLEAN
1616: ScsiClassInterpretSenseInfo(
1617: IN PDEVICE_OBJECT DeviceObject,
1618: IN PSCSI_REQUEST_BLOCK Srb,
1619: IN UCHAR MajorFunctionCode,
1620: IN ULONG IoDeviceCode,
1621: IN ULONG RetryCount,
1622: OUT NTSTATUS *Status
1623: )
1624:
1625: /*++
1626:
1627: Routine Description:
1628:
1629: This routine interprets the data returned from the SCSI
1630: request sense. It determines the status to return in the
1631: IRP and whether this request can be retried.
1632:
1633: Arguments:
1634:
1635: DeviceObject - Supplies the device object associated with this request.
1636:
1637: Srb - Supplies the scsi request block which failed.
1638:
1639: MajorFunctionCode - Supplies the function code to be used for logging.
1640:
1641: IoDeviceCode - Supplies the device code to be used for logging.
1642:
1643: Status - Returns the status for the request.
1644:
1645: Return Value:
1646:
1647: BOOLEAN TRUE: Drivers should retry this request.
1648: FALSE: Drivers should not retry this request.
1649:
1650: --*/
1651:
1652: {
1653: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1654: PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
1655: BOOLEAN retry;
1656: BOOLEAN logError;
1657: ULONG uniqueId;
1658: NTSTATUS logStatus;
1659: PIO_ERROR_LOG_PACKET errorLogEntry;
1660: ULONG badSector;
1661: ULONG readSector;
1662: ULONG index;
1663:
1664: logError = FALSE;
1665: retry = TRUE;
1666: badSector = 0;
1667:
1668: //
1669: // Check that request sense buffer is valid.
1670: //
1671:
1672: if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID &&
1673: Srb->SenseInfoBufferLength >= offsetof(SENSE_DATA, CommandSpecificInformation)) {
1674:
1675: DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
1676: senseBuffer->ErrorCode));
1677: DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
1678: senseBuffer->SenseKey));
1679: DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
1680: senseBuffer->AdditionalSenseCode));
1681: DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
1682: senseBuffer->AdditionalSenseCodeQualifier));
1683:
1684: //
1685: // Zero the additional sense code and additional sense code qualifier
1686: // if they were not returned by the device.
1687: //
1688:
1689: readSector = senseBuffer->AdditionalSenseLength +
1690: offsetof(SENSE_DATA, AdditionalSenseLength);
1691:
1692: if (readSector > Srb->SenseInfoBufferLength) {
1693: readSector = Srb->SenseInfoBufferLength;
1694: }
1695:
1696: if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCode)) {
1697: senseBuffer->AdditionalSenseCode = 0;
1698: }
1699:
1700: if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCodeQualifier)) {
1701: senseBuffer->AdditionalSenseCodeQualifier = 0;
1702: }
1703:
1704: switch (senseBuffer->SenseKey & 0xf) {
1705:
1706: case SCSI_SENSE_NOT_READY:
1707:
1708: DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
1709: *Status = STATUS_DEVICE_NOT_READY;
1710:
1711: switch (senseBuffer->AdditionalSenseCode) {
1712:
1713: case SCSI_ADSENSE_LUN_NOT_READY:
1714:
1715: DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
1716:
1717: switch (senseBuffer->AdditionalSenseCodeQualifier) {
1718:
1719: case SCSI_SENSEQ_BECOMING_READY:
1720:
1721: DebugPrint((1, "ScsiClassInterpretSenseInfo:"
1722: " In process of becoming ready\n"));
1723: break;
1724:
1725: case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
1726:
1727: DebugPrint((1, "ScsiClassInterpretSenseInfo:"
1728: " Manual intervention required\n"));
1729: *Status = STATUS_NO_MEDIA_IN_DEVICE;
1730: retry = FALSE;
1731: break;
1732:
1733: case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
1734:
1735: DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
1736: retry = FALSE;
1737: break;
1738:
1739: case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
1740: default:
1741:
1742: DebugPrint((1, "ScsiClassInterpretSenseInfo:"
1743: " Initializing command required\n"));
1744:
1745: //
1746: // This sense code/additional sense code
1747: // combination may indicate that the device
1748: // needs to be started. Send an start unit if this
1749: // is a disk device.
1750: //
1751:
1752: if (DeviceObject->DeviceType == FILE_DEVICE_DISK) {
1753: StartUnit(DeviceObject);
1754: }
1755:
1756: break;
1757:
1758: } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
1759:
1760: break;
1761:
1762: case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
1763:
1764: DebugPrint((1,
1765: "ScsiClassInterpretSenseInfo:"
1766: " No Media in device.\n"));
1767: *Status = STATUS_NO_MEDIA_IN_DEVICE;
1768: retry = FALSE;
1769: break;
1770:
1771: } // end switch (senseBuffer->AdditionalSenseCode)
1772:
1773: break;
1774:
1775: case SCSI_SENSE_DATA_PROTECT:
1776:
1777: DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
1778: *Status = STATUS_MEDIA_WRITE_PROTECTED;
1779: retry = FALSE;
1780: break;
1781:
1782: case SCSI_SENSE_MEDIUM_ERROR:
1783:
1784: DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
1785: *Status = STATUS_DEVICE_DATA_ERROR;
1786:
1787: retry = FALSE;
1788: logError = TRUE;
1789: uniqueId = 256;
1790: logStatus = IO_ERR_BAD_BLOCK;
1791: break;
1792:
1793: case SCSI_SENSE_HARDWARE_ERROR:
1794:
1795: DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
1796: *Status = STATUS_IO_DEVICE_ERROR;
1797:
1798: logError = TRUE;
1799: uniqueId = 257;
1800: logStatus = IO_ERR_CONTROLLER_ERROR;
1801:
1802: break;
1803:
1804: case SCSI_SENSE_ILLEGAL_REQUEST:
1805:
1806: DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
1807: *Status = STATUS_INVALID_DEVICE_REQUEST;
1808:
1809: switch (senseBuffer->AdditionalSenseCode) {
1810:
1811: case SCSI_ADSENSE_ILLEGAL_COMMAND:
1812: DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
1813: break;
1814:
1815: case SCSI_ADSENSE_ILLEGAL_BLOCK:
1816: DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
1817: *Status = STATUS_NONEXISTENT_SECTOR;
1818: break;
1819:
1820: case SCSI_ADSENSE_INVALID_LUN:
1821: DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
1822: *Status = STATUS_NO_SUCH_DEVICE;
1823: break;
1824:
1825: case SCSI_ADSENSE_MUSIC_AREA:
1826: DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
1827: break;
1828:
1829: case SCSI_ADSENSE_DATA_AREA:
1830: DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
1831: break;
1832:
1833: case SCSI_ADSENSE_VOLUME_OVERFLOW:
1834: DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
1835: break;
1836:
1837: } // end switch (senseBuffer->AdditionalSenseCode)
1838:
1839: retry = FALSE;
1840:
1841: break;
1842:
1843: case SCSI_SENSE_UNIT_ATTENTION:
1844:
1845: switch (senseBuffer->AdditionalSenseCode) {
1846: case SCSI_ADSENSE_MEDIUM_CHANGED:
1847: DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
1848: break;
1849:
1850: case SCSI_ADSENSE_BUS_RESET:
1851: DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
1852: break;
1853:
1854: default:
1855: DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
1856: break;
1857:
1858: } // end switch (senseBuffer->AdditionalSenseCode)
1859:
1860: if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
1861: DeviceObject->Vpb->Flags & VPB_MOUNTED) {
1862:
1863: //
1864: // Set bit to indicate that media may have changed
1865: // and volume needs verification.
1866: //
1867:
1868: DeviceObject->Flags |= DO_VERIFY_VOLUME;
1869:
1870: *Status = STATUS_VERIFY_REQUIRED;
1871: retry = FALSE;
1872:
1873: } else {
1874:
1875: *Status = STATUS_IO_DEVICE_ERROR;
1876:
1877: }
1878:
1879: break;
1880:
1881: case SCSI_SENSE_ABORTED_COMMAND:
1882:
1883: DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
1884: *Status = STATUS_IO_DEVICE_ERROR;
1885: break;
1886:
1887: case SCSI_SENSE_RECOVERED_ERROR:
1888:
1889: DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
1890: *Status = STATUS_SUCCESS;
1891: retry = FALSE;
1892: logError = TRUE;
1893: uniqueId = 258;
1894:
1895: switch(senseBuffer->AdditionalSenseCode) {
1896: case SCSI_ADSENSE_SEEK_ERROR:
1897: case SCSI_ADSENSE_TRACK_ERROR:
1898: logStatus = IO_ERR_SEEK_ERROR;
1899: break;
1900:
1901: case SCSI_ADSENSE_REC_DATA_NOECC:
1902: case SCSI_ADSENSE_REC_DATA_ECC:
1903: logStatus = STATUS_DEVICE_DATA_ERROR;
1904: break;
1905:
1906: default:
1907: logStatus = IO_ERR_CONTROLLER_ERROR;
1908: break;
1909:
1910: } // end switch(senseBuffer->AdditionalSenseCode)
1911:
1912: if (senseBuffer->IncorrectLength) {
1913:
1914: DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
1915: *Status = STATUS_INVALID_BLOCK_LENGTH ;
1916: }
1917:
1918: break;
1919:
1920: case SCSI_SENSE_NO_SENSE:
1921:
1922: //
1923: // Check other indicators.
1924: //
1925:
1926: if (senseBuffer->IncorrectLength) {
1927:
1928: DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
1929: *Status = STATUS_INVALID_BLOCK_LENGTH ;
1930: retry = FALSE;
1931:
1932: } else {
1933:
1934: DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
1935: *Status = STATUS_IO_DEVICE_ERROR;
1936: retry = TRUE;
1937: }
1938:
1939: break;
1940:
1941: default:
1942:
1943: DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
1944: *Status = STATUS_IO_DEVICE_ERROR;
1945: break;
1946:
1947: } // end switch (senseBuffer->SenseKey & 0xf)
1948:
1949: //
1950: // Try to determine the bad sector from the inquiry data.
1951: //
1952:
1953: if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ ||
1954: ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY ||
1955: ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) {
1956:
1957: for (index = 0; index < 4; index++) {
1958: badSector = (badSector << 8) | senseBuffer->Information[index];
1959: }
1960:
1961: readSector = 0;
1962: for (index = 0; index < 4; index++) {
1963: readSector = (readSector << 8) | Srb->Cdb[index+2];
1964: }
1965:
1966: index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) |
1967: ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb;
1968:
1969: //
1970: // Make sure the bad sector is within the read sectors.
1971: //
1972:
1973: if (!(badSector >= readSector && badSector < readSector + index)) {
1974: badSector = readSector;
1975: }
1976: }
1977:
1978: } else {
1979:
1980: //
1981: // Request sense buffer not valid. No sense information
1982: // to pinpoint the error. Return general request fail.
1983: //
1984:
1985: DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
1986: SRB_STATUS(Srb->SrbStatus)));
1987: retry = TRUE;
1988:
1989: switch (SRB_STATUS(Srb->SrbStatus)) {
1990: case SRB_STATUS_INVALID_LUN:
1991: case SRB_STATUS_INVALID_TARGET_ID:
1992: case SRB_STATUS_NO_DEVICE:
1993: case SRB_STATUS_NO_HBA:
1994: case SRB_STATUS_INVALID_PATH_ID:
1995: *Status = STATUS_NO_SUCH_DEVICE;
1996: retry = FALSE;
1997: break;
1998:
1999: case SRB_STATUS_COMMAND_TIMEOUT:
2000: case SRB_STATUS_ABORTED:
2001: case SRB_STATUS_TIMEOUT:
2002:
2003: //
2004: // Update the error count for the device.
2005: //
2006:
2007: deviceExtension->ErrorCount++;
2008:
2009: *Status = STATUS_IO_TIMEOUT;
2010: break;
2011:
2012: case SRB_STATUS_SELECTION_TIMEOUT:
2013: logError = TRUE;
2014: logStatus = IO_ERR_NOT_READY;
2015: uniqueId = 260;
2016: *Status = STATUS_DEVICE_NOT_CONNECTED;
2017: retry = FALSE;
2018: break;
2019:
2020: case SRB_STATUS_DATA_OVERRUN:
2021: *Status = STATUS_DATA_OVERRUN;
2022: retry = FALSE;
2023: break;
2024:
2025: case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
2026:
2027: //
2028: // Update the error count for the device.
2029: //
2030:
2031: deviceExtension->ErrorCount++;
2032: *Status = STATUS_IO_DEVICE_ERROR;
2033:
2034: //
2035: // If there was phase sequence error then limit the number of
2036: // retries.
2037: //
2038:
2039: if (RetryCount > 1 ) {
2040: retry = FALSE;
2041: }
2042:
2043: break;
2044:
2045: case SRB_STATUS_REQUEST_FLUSHED:
2046:
2047: //
2048: // If the status needs verification bit is set. Then set
2049: // the status to need verification and no retry; otherwise,
2050: // just retry the request.
2051: //
2052:
2053: if (DeviceObject->Flags & DO_VERIFY_VOLUME ) {
2054:
2055: *Status = STATUS_VERIFY_REQUIRED;
2056: retry = FALSE;
2057: } else {
2058: *Status = STATUS_IO_DEVICE_ERROR;
2059: }
2060:
2061: break;
2062:
2063: case SRB_STATUS_INVALID_REQUEST:
2064:
2065: //
2066: // An invalid request was attempted.
2067: //
2068:
2069: *Status = STATUS_INVALID_DEVICE_REQUEST;
2070: retry = FALSE;
2071: break;
2072:
2073: case SRB_STATUS_UNEXPECTED_BUS_FREE:
2074: case SRB_STATUS_PARITY_ERROR:
2075:
2076: //
2077: // Update the error count for the device.
2078: //
2079:
2080: deviceExtension->ErrorCount++;
2081:
2082: //
2083: // Fall through to below.
2084: //
2085:
2086: case SRB_STATUS_BUS_RESET:
2087: *Status = STATUS_IO_DEVICE_ERROR;
2088: break;
2089:
2090: case SRB_STATUS_ERROR:
2091:
2092: *Status = STATUS_IO_DEVICE_ERROR;
2093: if (Srb->ScsiStatus == 0) {
2094:
2095: //
2096: // This is some strange return code. Update the error
2097: // count for the device.
2098: //
2099:
2100: deviceExtension->ErrorCount++;
2101:
2102: } if (Srb->ScsiStatus == SCSISTAT_BUSY) {
2103:
2104: *Status = STATUS_DEVICE_NOT_READY;
2105:
2106: } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) {
2107:
2108: *Status = STATUS_DEVICE_BUSY;
2109: retry = FALSE;
2110:
2111: }
2112:
2113: break;
2114:
2115: default:
2116: logError = TRUE;
2117: logStatus = IO_ERR_CONTROLLER_ERROR;
2118: uniqueId = 259;
2119: *Status = STATUS_IO_DEVICE_ERROR;
2120: break;
2121:
2122: }
2123:
2124: //
2125: // If the error count has exceeded the error limit, the disable
2126: // any tagged queuing, multiple requests per lu queueing
2127: // and sychronous data transfers.
2128: //
2129:
2130: if (deviceExtension->ErrorCount == 4) {
2131:
2132: //
2133: // Clearing the no queue freeze flag prevents the port driver
2134: // from sending multiple requests per logical unit.
2135: //
2136:
2137: deviceExtension->SrbFlags &= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE |
2138: SRB_FLAGS_NO_QUEUE_FREEZE);
2139:
2140: deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2141: DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
2142:
2143: } else if (deviceExtension->ErrorCount == 8) {
2144:
2145: //
2146: // If a second threshold is reached, disable disconnects.
2147: //
2148:
2149: deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
2150: DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
2151: }
2152: }
2153:
2154: //
2155: // If there is a class specific error handler call it.
2156: //
2157:
2158: if (deviceExtension->ClassError != NULL) {
2159:
2160: deviceExtension->ClassError(DeviceObject,
2161: Srb,
2162: Status,
2163: &retry);
2164: }
2165:
2166: //
2167: // Log an error if necessary.
2168: //
2169:
2170: if (logError) {
2171:
2172: errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
2173: DeviceObject,
2174: sizeof(IO_ERROR_LOG_PACKET) + 5 * sizeof(ULONG));
2175:
2176: if (errorLogEntry == NULL) {
2177:
2178: //
2179: // Return if no packet could be allocated.
2180: //
2181:
2182: return retry;
2183:
2184: }
2185:
2186: if (retry && RetryCount < MAXIMUM_RETRIES) {
2187: errorLogEntry->FinalStatus = STATUS_SUCCESS;
2188: } else {
2189: errorLogEntry->FinalStatus = *Status;
2190: }
2191:
2192: //
2193: // Calculate the device offset if there is a geometry.
2194: //
2195:
2196: if (deviceExtension->DiskGeometry != NULL) {
2197:
2198: errorLogEntry->DeviceOffset = LiFromLong(
2199: badSector);
2200: errorLogEntry->DeviceOffset = RtlExtendedIntegerMultiply(
2201: errorLogEntry->DeviceOffset,
2202: deviceExtension->DiskGeometry->BytesPerSector);
2203: }
2204:
2205: errorLogEntry->ErrorCode = logStatus;
2206: errorLogEntry->SequenceNumber = 0;
2207: errorLogEntry->MajorFunctionCode = MajorFunctionCode;
2208: errorLogEntry->IoControlCode = IoDeviceCode;
2209: errorLogEntry->RetryCount = (UCHAR) RetryCount;
2210: errorLogEntry->UniqueErrorValue = uniqueId;
2211: errorLogEntry->DumpDataSize = 6 * sizeof(ULONG);
2212: errorLogEntry->DumpData[0] = Srb->PathId;
2213: errorLogEntry->DumpData[1] = Srb->TargetId;
2214: errorLogEntry->DumpData[2] = Srb->Lun;
2215: errorLogEntry->DumpData[3] = 0;
2216: errorLogEntry->DumpData[4] = Srb->SrbStatus << 8 | Srb->ScsiStatus;
2217:
2218: if (senseBuffer != NULL) {
2219: errorLogEntry->DumpData[5] = senseBuffer->SenseKey << 16 |
2220: senseBuffer->AdditionalSenseCode << 8 |
2221: senseBuffer->AdditionalSenseCodeQualifier;
2222:
2223: }
2224:
2225: //
2226: // Write the error log packet.
2227: //
2228:
2229: IoWriteErrorLogEntry(errorLogEntry);
2230: }
2231:
2232: return retry;
2233:
2234: } // end ScsiClassInterpretSenseInfo()
2235:
2236:
2237: VOID
2238: RetryRequest(
2239: PDEVICE_OBJECT DeviceObject,
2240: PIRP Irp,
2241: PSCSI_REQUEST_BLOCK Srb,
2242: BOOLEAN Associated
2243: )
2244:
2245: /*++
2246:
2247: Routine Description:
2248:
2249: This routine reinitalizes the necessary fields, and sends the request
2250: to the port driver.
2251:
2252: Arguments:
2253:
2254: DeviceObject - Supplies the device object associated with this request.
2255:
2256: Irp - Supplies the request to be retried.
2257:
2258: Srb - Supplies a Pointer to the SCSI request block to be retied.
2259:
2260: Assocaiated - Indicates this is an assocatied Irp created by split request.
2261:
2262: Return Value:
2263:
2264: None
2265:
2266: --*/
2267:
2268: {
2269: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2270: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2271: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
2272: ULONG transferByteCount;
2273:
2274: //
2275: // Determine the transfer count of the request. If this is a read or a
2276: // write then the transfer count is in the Irp stack. Otherwise assume
2277: // the MDL contains the correct length. If there is no MDL then the
2278: // transfer length must be zero.
2279: //
2280:
2281: if (currentIrpStack->MajorFunction == IRP_MJ_READ ||
2282: currentIrpStack->MajorFunction == IRP_MJ_WRITE) {
2283:
2284: transferByteCount = currentIrpStack->Parameters.Read.Length;
2285:
2286: } else if (Irp->MdlAddress != NULL) {
2287:
2288: //
2289: // Note this assumes that only read and write requests are spilt and
2290: // other request do not need to be. If the data buffer address in
2291: // the MDL and the SRB don't match then transfer length is most
2292: // likely incorrect.
2293: //
2294:
2295: ASSERT(Srb->DataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress));
2296: transferByteCount = Irp->MdlAddress->ByteCount;
2297:
2298: } else {
2299:
2300: transferByteCount = 0;
2301: }
2302:
2303: //
2304: // Reset byte count of transfer in SRB Extension.
2305: //
2306:
2307: Srb->DataTransferLength = transferByteCount;
2308:
2309: //
2310: // Zero SRB statuses.
2311: //
2312:
2313: Srb->SrbStatus = Srb->ScsiStatus = 0;
2314:
2315: //
2316: // Set the no disconnect flag, disable synchronous data transfers and
2317: // disable tagged queuing. This fixes some errors.
2318: //
2319:
2320: Srb->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT |
2321: SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2322:
2323: Srb->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
2324:
2325: //
2326: // Set up major SCSI function.
2327: //
2328:
2329: nextIrpStack->MajorFunction = IRP_MJ_SCSI;
2330:
2331: //
2332: // Save SRB address in next stack for port driver.
2333: //
2334:
2335: nextIrpStack->Parameters.Scsi.Srb = Srb;
2336:
2337: //
2338: // Set up IoCompletion routine address.
2339: //
2340:
2341: if (Associated) {
2342:
2343: IoSetCompletionRoutine(Irp, ScsiClassIoCompleteAssociated, Srb, TRUE, TRUE, TRUE);
2344:
2345: } else {
2346:
2347: IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE);
2348:
2349: }
2350:
2351:
2352: //
2353: // Pass the request to the port driver.
2354: //
2355:
2356: (PVOID)IoCallDriver(deviceExtension->PortDeviceObject, Irp);
2357:
2358: } // end RetryRequest()
2359:
2360: VOID
2361: ScsiClassBuildRequest(
2362: PDEVICE_OBJECT DeviceObject,
2363: PIRP Irp
2364: )
2365:
2366: /*++
2367:
2368: Routine Description:
2369:
2370: This routine allocates and builds an Srb for a read or write request.
2371: The block address and length are supplied by the Irp. The retry count
2372: is stored in the current stack for use by ScsiClassIoComplete which
2373: processes these requests when they complete. The Irp is ready to be
2374: passed to the port driver when this routine returns.
2375:
2376: Arguments:
2377:
2378: DeviceObject - Supplies the device object associated with this request.
2379:
2380: Irp - Supplies the request to be retried.
2381:
2382: Note:
2383:
2384: If the IRP is for a disk transfer, the byteoffset field
2385: will already have been adjusted to make it relative to
2386: the beginning of the disk.
2387:
2388:
2389: Return Value:
2390:
2391: None.
2392:
2393: --*/
2394:
2395: {
2396: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2397: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2398: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
2399: PSCSI_REQUEST_BLOCK srb;
2400: PCDB cdb;
2401: ULONG logicalBlockAddress;
2402: LARGE_INTEGER startingOffset =
2403: currentIrpStack->Parameters.Read.ByteOffset;
2404: USHORT transferBlocks;
2405:
2406: //
2407: // Calculate relative sector address.
2408: //
2409:
2410: logicalBlockAddress = LiShr(startingOffset,
2411: deviceExtension->SectorShift).LowPart;
2412:
2413: //
2414: // Allocate an Srb.
2415: //
2416:
2417: if (deviceExtension->SrbZone != NULL &&
2418: (srb = ExInterlockedAllocateFromZone(
2419: deviceExtension->SrbZone,
2420: deviceExtension->SrbZoneSpinLock)) != NULL) {
2421:
2422: srb->SrbFlags = SRB_FLAGS_ALLOCATED_FROM_ZONE;
2423:
2424: } else {
2425:
2426: //
2427: // Allocate Srb from nonpaged pool.
2428: // This call must succeed.
2429: //
2430:
2431: srb = ExAllocatePool(NonPagedPoolMustSucceed, SCSI_REQUEST_BLOCK_SIZE);
2432:
2433: srb->SrbFlags = 0;
2434:
2435: }
2436:
2437: //
2438: // Write length to SRB.
2439: //
2440:
2441: srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2442:
2443: //
2444: // Set up IRP Address.
2445: //
2446:
2447: srb->OriginalRequest = Irp;
2448:
2449: //
2450: // Set up target ID and logical unit number.
2451: //
2452:
2453: srb->PathId = deviceExtension->PathId;
2454: srb->TargetId = deviceExtension->TargetId;
2455: srb->Lun = deviceExtension->Lun;
2456:
2457: srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2458:
2459: srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
2460:
2461: //
2462: // Save byte count of transfer in SRB Extension.
2463: //
2464:
2465: srb->DataTransferLength = currentIrpStack->Parameters.Read.Length;
2466:
2467: //
2468: // Initialize the queue actions field.
2469: //
2470:
2471: srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
2472:
2473: //
2474: // Queue sort key is Relative Block Address.
2475: //
2476:
2477: srb->QueueSortKey = logicalBlockAddress;
2478:
2479: //
2480: // Indicate auto request sense by specifying buffer and size.
2481: //
2482:
2483: srb->SenseInfoBuffer = deviceExtension->SenseData;
2484: srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
2485:
2486: //
2487: // Set timeout value in seconds.
2488: //
2489:
2490: srb->TimeOutValue = deviceExtension->TimeOutValue;
2491:
2492: //
2493: // Zero statuses.
2494: //
2495:
2496: srb->SrbStatus = srb->ScsiStatus = 0;
2497: srb->NextSrb = 0;
2498:
2499: //
2500: // Indicate that 10-byte CDB's will be used.
2501: //
2502:
2503: srb->CdbLength = 10;
2504:
2505: //
2506: // Fill in CDB fields.
2507: //
2508:
2509: cdb = (PCDB)srb->Cdb;
2510:
2511: RtlZeroMemory(cdb, srb->CdbLength);
2512:
2513: cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
2514:
2515: transferBlocks = (USHORT)(currentIrpStack->Parameters.Read.Length >> deviceExtension->SectorShift);
2516:
2517: //
2518: // Move little endian values into CDB in big endian format.
2519: //
2520:
2521: cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
2522: cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
2523: cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
2524: cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
2525:
2526: cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&transferBlocks)->Byte1;
2527: cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&transferBlocks)->Byte0;
2528:
2529: //
2530: // Set transfer direction flag and Cdb command.
2531: //
2532:
2533: if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
2534:
2535: DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
2536:
2537: srb->SrbFlags |= SRB_FLAGS_DATA_IN;
2538: cdb->CDB10.OperationCode = SCSIOP_READ;
2539:
2540: } else {
2541:
2542: DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
2543:
2544: srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
2545: cdb->CDB10.OperationCode = SCSIOP_WRITE;
2546: }
2547:
2548: //
2549: // If this is not a write-through request, then allow caching.
2550: //
2551:
2552: if (!(currentIrpStack->Flags & SL_WRITE_THROUGH)) {
2553:
2554: srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;
2555:
2556: } else {
2557:
2558: //
2559: // If write caching is enable then force media access in the
2560: // cdb.
2561: //
2562:
2563: if (deviceExtension->WriteCache) {
2564: cdb->CDB10.ForceUnitAccess = TRUE;
2565: }
2566: }
2567:
2568: //
2569: // Or in the default flags from the device object.
2570: //
2571:
2572: srb->SrbFlags |= deviceExtension->SrbFlags;
2573:
2574: //
2575: // Set up major SCSI function.
2576: //
2577:
2578: nextIrpStack->MajorFunction = IRP_MJ_SCSI;
2579:
2580: //
2581: // Save SRB address in next stack for port driver.
2582: //
2583:
2584: nextIrpStack->Parameters.Scsi.Srb = srb;
2585:
2586: //
2587: // Save retry count in current IRP stack.
2588: //
2589:
2590: currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
2591:
2592: //
2593: // Set up IoCompletion routine address.
2594: //
2595:
2596: IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
2597:
2598: return;
2599:
2600: } // end ScsiClassBuildRequest()
2601:
2602: ULONG
2603: ScsiClassModeSense(
2604: IN PDEVICE_OBJECT DeviceObject,
2605: IN PCHAR ModeSenseBuffer,
2606: IN ULONG Length,
2607: IN UCHAR PageMode
2608: )
2609:
2610: /*++
2611:
2612: Routine Description:
2613:
2614: This routine sends a mode sense command to a target ID and returns
2615: when it is complete.
2616:
2617: Arguments:
2618:
2619: DeviceObject - Supplies the device object associated with this request.
2620:
2621: ModeSenseBuffer - Supplies a buffer to store the sense data.
2622:
2623: Length - Supplies the length in bytes of the mode sense buffer.
2624:
2625: PageMode - Supplies the page or pages of mode sense data to be retrived.
2626:
2627: Return Value:
2628:
2629: Length of the transferred data is returned.
2630:
2631: --*/
2632: {
2633: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2634: PCDB cdb;
2635: SCSI_REQUEST_BLOCK srb;
2636: ULONG retries = 1;
2637: NTSTATUS status;
2638:
2639: RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
2640:
2641: //
2642: // Build the MODE SENSE CDB.
2643: //
2644:
2645: srb.CdbLength = 6;
2646: cdb = (PCDB)srb.Cdb;
2647:
2648: //
2649: // Set timeout value from device extension.
2650: //
2651:
2652: srb.TimeOutValue = deviceExtension->TimeOutValue;
2653:
2654: cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2655: cdb->MODE_SENSE.PageCode = PageMode;
2656: cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
2657:
2658: Retry:
2659:
2660: status = ScsiClassSendSrbSynchronous(DeviceObject,
2661: &srb,
2662: ModeSenseBuffer,
2663: Length,
2664: FALSE);
2665:
2666:
2667: if (status == STATUS_VERIFY_REQUIRED) {
2668:
2669: //
2670: // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
2671: // this status. MODE SENSE commands should be retried anyway.
2672: //
2673:
2674: if (retries--) {
2675:
2676: //
2677: // Retry request.
2678: //
2679:
2680: goto Retry;
2681: }
2682:
2683: } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
2684: status = STATUS_SUCCESS;
2685: }
2686:
2687: if (NT_SUCCESS(status)) {
2688: return(srb.DataTransferLength);
2689: } else {
2690: return(0);
2691: }
2692:
2693: } // end ScsiClassModeSense()
2694:
2695: PVOID
2696: ScsiClassFindModePage(
2697: IN PCHAR ModeSenseBuffer,
2698: IN ULONG Length,
2699: IN UCHAR PageMode
2700: )
2701:
2702: /*++
2703:
2704: Routine Description:
2705:
2706: This routine scans through the mode sense data and finds the requested
2707: mode sense page code.
2708:
2709: Arguments:
2710: ModeSenseBuffer - Supplies a pointer to the mode sense data.
2711:
2712: Length - Indicates the length of valid data.
2713:
2714: PageMode - Supplies the page mode to be searched for.
2715:
2716: Return Value:
2717:
2718: A pointer to the the requested mode page. If the mode page was not found
2719: then NULL is return.
2720:
2721: --*/
2722: {
2723: PUCHAR limit;
2724:
2725: limit = ModeSenseBuffer + Length;
2726:
2727: //
2728: // Skip the mode select header and block descriptors.
2729: //
2730:
2731: if (Length < sizeof(MODE_PARAMETER_HEADER)) {
2732: return(NULL);
2733: }
2734:
2735: ModeSenseBuffer += sizeof(MODE_PARAMETER_HEADER) +
2736: ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength;
2737:
2738: //
2739: // ModeSenseBuffer now points at pages. Walk the pages looking for the
2740: // requested page until the limit is reached.
2741: //
2742:
2743: while (ModeSenseBuffer < limit) {
2744:
2745: if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) {
2746: return(ModeSenseBuffer);
2747: }
2748:
2749: //
2750: // Adavance to the next page.
2751: //
2752:
2753: ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 2;
2754: }
2755:
2756: return(NULL);
2757:
2758: }
2759:
2760: NTSTATUS
2761: ScsiClassSendSrbAsynchronous(
2762: PDEVICE_OBJECT DeviceObject,
2763: PSCSI_REQUEST_BLOCK Srb,
2764: PIRP Irp,
2765: PVOID BufferAddress,
2766: ULONG BufferLength,
2767: BOOLEAN WriteToDevice
2768: )
2769: /*++
2770:
2771: Routine Description:
2772:
2773: This routine takes a partially built Srb and an Irp and sends it down to
2774: the port driver.
2775:
2776: Arguments:
2777: DeviceObject - Supplies the device object for the orginal request.
2778:
2779: Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
2780: CDB and the SRB timeout value must be filled in. The SRB must not be
2781: allocated from zone.
2782:
2783: Irp - Supplies the requesting Irp.
2784:
2785: BufferAddress - Supplies a pointer to the buffer to be transfered.
2786:
2787: BufferLength - Supplies the length of data transfer.
2788:
2789: WriteToDevice - Indicates the data transfer will be from system memory to
2790: device.
2791:
2792: Return Value:
2793:
2794: Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
2795:
2796: --*/
2797: {
2798:
2799: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2800: PIO_STACK_LOCATION irpStack;
2801:
2802: //
2803: // Write length to SRB.
2804: //
2805:
2806: Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2807:
2808: //
2809: // Set SCSI bus address.
2810: //
2811:
2812: Srb->PathId = deviceExtension->PathId;
2813: Srb->TargetId = deviceExtension->TargetId;
2814: Srb->Lun = deviceExtension->Lun;
2815:
2816: Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2817:
2818: //
2819: // This is a violation of the SCSI spec but it is required for
2820: // some targets.
2821: //
2822:
2823: Srb->Cdb[1] |= deviceExtension->Lun << 5;
2824:
2825: //
2826: // Indicate auto request sense by specifying buffer and size.
2827: //
2828:
2829: Srb->SenseInfoBuffer = deviceExtension->SenseData;
2830:
2831: Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
2832:
2833: Srb->DataBuffer = BufferAddress;
2834:
2835: if (BufferAddress != NULL) {
2836:
2837: //
2838: // Build Mdl if necessary.
2839: //
2840:
2841: if (Irp->MdlAddress == NULL) {
2842:
2843: if (IoAllocateMdl(BufferAddress,
2844: BufferLength,
2845: FALSE,
2846: FALSE,
2847: Irp) == NULL) {
2848:
2849: return(STATUS_INSUFFICIENT_RESOURCES);
2850: }
2851:
2852: MmBuildMdlForNonPagedPool(Irp->MdlAddress);
2853:
2854: } else {
2855:
2856: //
2857: // Make sure the buffer requested matches the MDL.
2858: //
2859:
2860: ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress));
2861: }
2862:
2863: //
2864: // Set read flag.
2865: //
2866:
2867: Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
2868:
2869: } else {
2870:
2871: //
2872: // Clear flags.
2873: //
2874:
2875: Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
2876: }
2877:
2878: //
2879: // Disable synchronous transfer for these requests.
2880: //
2881:
2882: Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2883:
2884: //
2885: // Set the transfer length.
2886: //
2887:
2888: Srb->DataTransferLength = BufferLength;
2889:
2890: //
2891: // Zero out status.
2892: //
2893:
2894: Srb->ScsiStatus = Srb->SrbStatus = 0;
2895:
2896: Srb->NextSrb = 0;
2897:
2898: //
2899: // Save a few parameters in the current stack location.
2900: //
2901:
2902: irpStack = IoGetCurrentIrpStackLocation(Irp);
2903:
2904: //
2905: // Save retry count in current Irp stack.
2906: //
2907:
2908: irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
2909:
2910: //
2911: // Set up IoCompletion routine address.
2912: //
2913:
2914: IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE);
2915:
2916: //
2917: // Get next stack location and
2918: // set major function code.
2919: //
2920:
2921: irpStack = IoGetNextIrpStackLocation(Irp);
2922:
2923: irpStack->MajorFunction = IRP_MJ_SCSI;
2924:
2925: //
2926: // Save SRB address in next stack for port driver.
2927: //
2928:
2929: irpStack->Parameters.Scsi.Srb = Srb;
2930:
2931: //
2932: // Set up Irp Address.
2933: //
2934:
2935: Srb->OriginalRequest = Irp;
2936:
2937: //
2938: // Call the port driver to process the request.
2939: //
2940:
2941: return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
2942:
2943: }
2944:
2945: NTSTATUS
2946: ScsiClassDeviceControl(
2947: PDEVICE_OBJECT DeviceObject,
2948: PIRP Irp
2949: )
2950: /*++
2951:
2952: Routine Description:
2953:
2954: The routine is the common class driver device control dispatch function.
2955: This routine is called by a class driver when it get an unrecognized
2956: device control request. This routine will perform the correct action for
2957: common requests such as lock media. If the device request is unknown it
2958: passed down to the next level.
2959:
2960: Arguments:
2961:
2962: DeviceObject - Supplies a pointer to the device object for this request.
2963:
2964: Irp - Supplies the Irp making the request.
2965:
2966: Return Value:
2967:
2968: Returns back a STATUS_PENDING or a completion status.
2969:
2970: --*/
2971:
2972: {
2973: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
2974: PIO_STACK_LOCATION nextStack;
2975: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2976: PSCSI_REQUEST_BLOCK srb;
2977: PCDB cdb;
2978: NTSTATUS status;
2979: ULONG modifiedIoControlCode;
2980:
2981: //
2982: // If this is a pass through I/O control, set the minor function code
2983: // and device address and pass it to the port driver.
2984: //
2985:
2986: if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH
2987: || irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) {
2988:
2989: PSCSI_PASS_THROUGH scsiPass;
2990:
2991: nextStack = IoGetNextIrpStackLocation(Irp);
2992:
2993: //
2994: // Validiate the user buffer.
2995: //
2996:
2997: if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)){
2998:
2999: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
3000: IoCompleteRequest(Irp, IO_NO_INCREMENT);
3001: return(STATUS_INVALID_PARAMETER);
3002:
3003: }
3004:
3005: //
3006: // Force the SCSI address to the correct value.
3007: //
3008:
3009: scsiPass = Irp->AssociatedIrp.SystemBuffer;
3010: scsiPass->PathId = deviceExtension->PathId;
3011: scsiPass->TargetId = deviceExtension->TargetId;
3012: scsiPass->Lun = deviceExtension->Lun;
3013:
3014: //
3015: // NOTICE: The SCSI-II specificaiton indicates that this field
3016: // should be zero; however, some target controllers ignore the logical
3017: // unit number in the INDENTIFY message and only look at the logical
3018: // unit number field in the CDB.
3019: //
3020:
3021: scsiPass->Cdb[1] |= deviceExtension->Lun << 5;
3022:
3023: nextStack->Parameters = irpStack->Parameters;
3024: nextStack->MajorFunction = irpStack->MajorFunction;
3025: nextStack->MinorFunction = IRP_MN_SCSI_CLASS;
3026:
3027: return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3028: }
3029:
3030: if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_ADDRESS) {
3031:
3032: PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer;
3033:
3034: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
3035: sizeof(SCSI_ADDRESS)) {
3036:
3037: //
3038: // Indicate unsuccessful status and no data transferred.
3039: //
3040:
3041: Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
3042: Irp->IoStatus.Information = 0;
3043: IoCompleteRequest(Irp, IO_NO_INCREMENT);
3044: return(STATUS_BUFFER_TOO_SMALL);
3045:
3046: }
3047:
3048: scsiAddress->Length = sizeof(SCSI_ADDRESS);
3049: scsiAddress->PortNumber = deviceExtension->PortNumber;
3050: scsiAddress->PathId = deviceExtension->PathId;
3051: scsiAddress->TargetId = deviceExtension->TargetId;
3052: scsiAddress->Lun = deviceExtension->Lun;
3053: Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
3054: Irp->IoStatus.Status = STATUS_SUCCESS;
3055: IoCompleteRequest(Irp, IO_NO_INCREMENT);
3056: return(STATUS_SUCCESS);
3057:
3058: }
3059:
3060: srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
3061:
3062: if (srb == NULL) {
3063:
3064: Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3065: IoCompleteRequest(Irp, IO_NO_INCREMENT);
3066: return(STATUS_INSUFFICIENT_RESOURCES);
3067: }
3068:
3069: //
3070: // Write zeros to Srb.
3071: //
3072:
3073: RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
3074:
3075: cdb = (PCDB)srb->Cdb;
3076:
3077: //
3078: // Change the device type to disk for the switch statement.
3079: //
3080:
3081: modifiedIoControlCode = (irpStack->Parameters.DeviceIoControl.IoControlCode
3082: & ~0xffff0000) | (IOCTL_DISK_BASE << 16);
3083:
3084: switch (modifiedIoControlCode) {
3085:
3086: case IOCTL_DISK_CHECK_VERIFY:
3087:
3088: //
3089: // Test Unit Ready
3090: //
3091:
3092: DebugPrint((3,"ScsiDeviceIoControl: Check verify\n"));
3093:
3094: srb->CdbLength = 6;
3095:
3096: cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
3097:
3098: //
3099: // Set timeout value.
3100: //
3101:
3102: srb->TimeOutValue = deviceExtension->TimeOutValue;
3103:
3104: status = ScsiClassSendSrbAsynchronous(DeviceObject,
3105: srb,
3106: Irp,
3107: NULL,
3108: 0,
3109: FALSE);
3110:
3111: return(status);
3112:
3113: case IOCTL_DISK_MEDIA_REMOVAL:
3114:
3115: {
3116:
3117: PPREVENT_MEDIA_REMOVAL MediaRemoval =
3118: Irp->AssociatedIrp.SystemBuffer;
3119:
3120: //
3121: // Prevent/Allow media removal.
3122: //
3123:
3124: DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
3125:
3126: if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
3127: sizeof(PREVENT_MEDIA_REMOVAL)) {
3128:
3129: //
3130: // Indicate unsuccessful status and no data transferred.
3131: //
3132:
3133: Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
3134: Irp->IoStatus.Information = 0;
3135: ExFreePool(srb);
3136: IoCompleteRequest(Irp, IO_NO_INCREMENT);
3137: return(STATUS_BUFFER_TOO_SMALL);
3138: }
3139:
3140: srb->CdbLength = 6;
3141:
3142: cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
3143:
3144: //
3145: // TRUE - prevent media removal.
3146: // FALSE - allow media removal.
3147: //
3148:
3149: cdb->MEDIA_REMOVAL.Prevent = MediaRemoval->PreventMediaRemoval;
3150:
3151: //
3152: // Set timeout value.
3153: //
3154:
3155: srb->TimeOutValue = deviceExtension->TimeOutValue;
3156:
3157: status = ScsiClassSendSrbAsynchronous(DeviceObject,
3158: srb,
3159: Irp,
3160: NULL,
3161: 0,
3162: FALSE);
3163:
3164: return(status);
3165:
3166: }
3167:
3168: case IOCTL_DISK_RESERVE:
3169:
3170: //
3171: // Reserve logical unit.
3172: //
3173:
3174: srb->CdbLength = 6;
3175:
3176: cdb->CDB6GENERIC.OperationCode = SCSIOP_RESERVE_UNIT;
3177:
3178: //
3179: // Set timeout value.
3180: //
3181:
3182: srb->TimeOutValue = deviceExtension->TimeOutValue;
3183:
3184: status = ScsiClassSendSrbAsynchronous(DeviceObject,
3185: srb,
3186: Irp,
3187: NULL,
3188: 0,
3189: FALSE);
3190:
3191: return(status);
3192: break;
3193:
3194: case IOCTL_DISK_RELEASE:
3195:
3196: //
3197: // Release logical unit.
3198: //
3199:
3200: srb->CdbLength = 6;
3201:
3202: cdb->CDB6GENERIC.OperationCode = SCSIOP_RELEASE_UNIT;
3203:
3204: //
3205: // Set timeout value.
3206: //
3207:
3208: srb->TimeOutValue = deviceExtension->TimeOutValue;
3209:
3210: status = ScsiClassSendSrbAsynchronous(DeviceObject,
3211: srb,
3212: Irp,
3213: NULL,
3214: 0,
3215: FALSE);
3216:
3217: return(status);
3218: break;
3219:
3220: case IOCTL_DISK_EJECT_MEDIA:
3221:
3222: //
3223: // Eject media.
3224: //
3225:
3226: srb->CdbLength = 6;
3227:
3228: cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
3229:
3230: cdb->START_STOP.LoadEject = 1;
3231: cdb->START_STOP.Start = 0;
3232:
3233: //
3234: // Set timeout value.
3235: //
3236:
3237: srb->TimeOutValue = deviceExtension->TimeOutValue;
3238:
3239: status = ScsiClassSendSrbAsynchronous(DeviceObject,
3240: srb,
3241: Irp,
3242: NULL,
3243: 0,
3244: FALSE);
3245:
3246: return(status);
3247: break;
3248:
3249: case IOCTL_DISK_LOAD_MEDIA:
3250:
3251: //
3252: // Load media.
3253: //
3254:
3255: DebugPrint((3,"CdRomDeviceControl: Load media\n"));
3256:
3257: srb->CdbLength = 6;
3258:
3259: cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
3260:
3261: cdb->START_STOP.LoadEject = 0;
3262: cdb->START_STOP.Start = 0;
3263:
3264: //
3265: // Set timeout value.
3266: //
3267:
3268: srb->TimeOutValue = deviceExtension->TimeOutValue;
3269:
3270: status = ScsiClassSendSrbAsynchronous(DeviceObject,
3271: srb,
3272: Irp,
3273: NULL,
3274: 0,
3275: FALSE);
3276:
3277: return(status);
3278: break;
3279:
3280: default:
3281:
3282: DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
3283:
3284: //
3285: // Pass the device control to the next driver.
3286: //
3287:
3288: ExFreePool(srb);
3289:
3290: //
3291: // Copy the Irp stack parameters to the next stack location.
3292: //
3293:
3294: nextStack = IoGetNextIrpStackLocation(Irp);
3295:
3296: nextStack->Parameters = irpStack->Parameters;
3297: nextStack->MajorFunction = irpStack->MajorFunction;
3298: nextStack->MinorFunction = irpStack->MinorFunction;
3299:
3300: return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3301: break;
3302:
3303: } // end switch( ...
3304:
3305: }
3306:
3307: NTSTATUS
3308: ScsiClassClaimDevice(
3309: IN PDEVICE_OBJECT PortDeviceObject,
3310: IN PSCSI_INQUIRY_DATA LunInfo,
3311: IN BOOLEAN Release,
3312: OUT PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL
3313: )
3314: /*++
3315:
3316: Routine Description:
3317:
3318: This function claims a device in the port driver. The port driver object
3319: is updated with the correct driver object if the device is successfully
3320: claimed.
3321:
3322: Arguments:
3323:
3324: PortDeviceObject - Supplies the base port device object.
3325:
3326: LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
3327:
3328: Release - Indicates the logical unit should be released rather than claimed.
3329:
3330: NewPortDeviceObject - Returns the updated port device object to be used
3331: for all future accesses.
3332:
3333: Return Value:
3334:
3335: Returns a status indicating success or failure of the operation.
3336:
3337: --*/
3338:
3339: {
3340: IO_STATUS_BLOCK ioStatus;
3341: PIRP irp;
3342: PIO_STACK_LOCATION irpStack;
3343: KEVENT event;
3344: NTSTATUS status;
3345: SCSI_REQUEST_BLOCK srb;
3346:
3347: if (NewPortDeviceObject != NULL) {
3348: *NewPortDeviceObject = NULL;
3349: }
3350:
3351: //
3352: // Clear the SRB fields.
3353: //
3354:
3355: RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3356:
3357: //
3358: // Write length to SRB.
3359: //
3360:
3361: srb.Length = SCSI_REQUEST_BLOCK_SIZE;
3362:
3363: //
3364: // Set SCSI bus address.
3365: //
3366:
3367: srb.PathId = LunInfo->PathId;
3368: srb.TargetId = LunInfo->TargetId;
3369: srb.Lun = LunInfo->Lun;
3370:
3371: srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE :
3372: SRB_FUNCTION_CLAIM_DEVICE;
3373:
3374: //
3375: // Set the event object to the unsignaled state.
3376: // It will be used to signal request completion.
3377: //
3378:
3379: KeInitializeEvent(&event, NotificationEvent, FALSE);
3380:
3381: //
3382: // Build synchronous request with no transfer.
3383: //
3384:
3385: irp = IoBuildDeviceIoControlRequest( IOCTL_SCSI_EXECUTE_NONE,
3386: PortDeviceObject,
3387: NULL,
3388: 0,
3389: NULL,
3390: 0,
3391: TRUE,
3392: &event,
3393: &ioStatus);
3394:
3395: if (irp == NULL) {
3396:
3397: DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
3398: return(STATUS_INSUFFICIENT_RESOURCES);
3399: }
3400:
3401: irpStack = IoGetNextIrpStackLocation(irp);
3402:
3403: //
3404: // Save SRB address in next stack for port driver.
3405: //
3406:
3407: irpStack->Parameters.Scsi.Srb = &srb;
3408:
3409: //
3410: // Set up IRP Address.
3411: //
3412:
3413: srb.OriginalRequest = irp;
3414:
3415: //
3416: // Call the port driver with the request and wait for it to complete.
3417: //
3418:
3419: status = IoCallDriver(PortDeviceObject, irp);
3420: if (status == STATUS_PENDING) {
3421:
3422: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
3423: status = ioStatus.Status;
3424: }
3425:
3426: //
3427: // If this is a release request, then just decrement the reference count
3428: // and return. The status does not matter.
3429: //
3430:
3431: if (Release) {
3432:
3433: ObDereferenceObject(PortDeviceObject);
3434: return(STATUS_SUCCESS);
3435: }
3436:
3437: if (!NT_SUCCESS(status)) {
3438: return(status);
3439: }
3440:
3441: ASSERT(srb.DataBuffer != NULL);
3442:
3443: //
3444: // Reference the new port driver object so that it will not go away while
3445: // it is being used.
3446: //
3447:
3448: status = ObReferenceObjectByPointer(srb.DataBuffer,
3449: 0,
3450: NULL,
3451: KernelMode );
3452:
3453: if (!NT_SUCCESS(status)) {
3454:
3455: return(status);
3456:
3457: }
3458:
3459: //
3460: // Return the new port device object pointer.
3461: //
3462:
3463: if (NewPortDeviceObject != NULL) {
3464: *NewPortDeviceObject = srb.DataBuffer;
3465: }
3466:
3467: return status;
3468:
3469: }
3470:
3471:
3472: NTSTATUS
3473: ScsiClassInternalIoControl (
3474: IN PDEVICE_OBJECT DeviceObject,
3475: IN PIRP Irp
3476: )
3477:
3478: /*++
3479:
3480: Routine Description:
3481:
3482: This routine passes internal device controls to the port driver.
3483: Internal device controls are used by higher level class drivers to
3484: send scsi requests to a device that are not normally sent by a generic
3485: class driver.
3486:
3487: The path ID, target ID and logical unit ID are set in the srb so the
3488: higher level driver does not have to figure out what values are actually
3489: used.
3490:
3491: Arguments:
3492:
3493: DeviceObject - Supplies a pointer to the device object for this request.
3494:
3495: Irp - Supplies the Irp making the request.
3496:
3497: Return Value:
3498:
3499: Returns back a STATUS_PENDING or a completion status.
3500:
3501: --*/
3502: {
3503: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
3504: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3505: PSCSI_REQUEST_BLOCK srb;
3506:
3507: //
3508: // Get a pointer to the SRB.
3509: //
3510:
3511: srb = irpStack->Parameters.Scsi.Srb;
3512:
3513: //
3514: // Set SCSI bus address.
3515: //
3516:
3517: srb->PathId = deviceExtension->PathId;
3518: srb->TargetId = deviceExtension->TargetId;
3519: srb->Lun = deviceExtension->Lun;
3520:
3521: //
3522: // NOTICE: The SCSI-II specificaiton indicates that this field should be
3523: // zero; however, some target controllers ignore the logical unit number
3524: // in the INDENTIFY message and only look at the logical unit number field
3525: // in the CDB.
3526: //
3527:
3528: srb->Cdb[1] |= deviceExtension->Lun << 5;
3529:
3530: //
3531: // Set the parameters in the next stack location.
3532: //
3533:
3534: irpStack = IoGetNextIrpStackLocation(Irp);
3535:
3536: irpStack->Parameters.Scsi.Srb = srb;
3537: irpStack->MajorFunction = IRP_MJ_SCSI;
3538: irpStack->MinorFunction = IRP_MN_SCSI_CLASS;
3539:
3540: IoSetCompletionRoutine(Irp, ClassIoCompletion, NULL, TRUE, TRUE, TRUE);
3541:
3542: return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3543: }
3544:
3545: NTSTATUS
3546: ClassIoCompletion(
3547: IN PDEVICE_OBJECT DeviceObject,
3548: IN PIRP Irp,
3549: IN PVOID Context
3550: )
3551:
3552: /*++
3553:
3554: Routine Description:
3555:
3556: This routine is called when an internal device control I/O request
3557: has completed. It marks the IRP pending if necessary and returns the
3558: status of the request.
3559:
3560: Arguments:
3561:
3562: DeviceObject - Target device object.
3563:
3564: Irp - Completed request.
3565:
3566: Context - not used.
3567:
3568: Return Value:
3569:
3570: Returns the status of the completed request.
3571:
3572: --*/
3573:
3574: {
3575: UNREFERENCED_PARAMETER(Context);
3576: UNREFERENCED_PARAMETER(DeviceObject);
3577:
3578:
3579: //
3580: // If pending is returned for this Irp then mark current stack
3581: // as pending
3582: //
3583:
3584: if (Irp->PendingReturned) {
3585:
3586: IoMarkIrpPending( Irp );
3587:
3588: }
3589:
3590: return Irp->IoStatus.Status;
3591:
3592: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.