|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991 Microsoft Corporation
4:
5: Module Name:
6:
7: tape.c
8:
9: Abstract:
10:
11: This is the tape class driver.
12:
13: Authors:
14:
15: Mike Glass
16: Hunter Small
17:
18: Environment:
19:
20: kernel mode only
21:
22: Revision History:
23:
24: --*/
25:
26: #include "ntddk.h"
27: #include "tape.h"
28:
29: //
30: // The following prototypes are the internal tape class routines.
31: //
32:
33: NTSTATUS
34: DriverEntry(
35: IN PDRIVER_OBJECT DriverObject,
36: IN PUNICODE_STRING RegistryPath
37: );
38:
39: VOID
40: UpdateTapeInformationInRegistry(
41: IN PDEVICE_OBJECT DeviceObject,
42: IN PSCSI_INQUIRY_DATA ScsiInquiryData,
43: IN ULONG PortNumber,
44: IN ULONG TapeNumber
45: );
46:
47: NTSTATUS
48: CreateTapeDeviceObject(
49: IN PDRIVER_OBJECT DriverObject,
50: IN PULONG DeviceCount,
51: IN PIO_SCSI_CAPABILITIES PortCapabilities,
52: IN PSCSI_INQUIRY_DATA LunInfo,
53: IN PDEVICE_OBJECT PortDeviceObject,
54: IN ULONG PortNumber
55: );
56:
57: BOOLEAN
58: FindScsiTapes(
59: IN PDRIVER_OBJECT DriverObject,
60: IN PDEVICE_OBJECT PortDeviceObject,
61: IN ULONG PortNumber
62: );
63:
64: VOID
65: SplitTapeRequest(
66: IN PDEVICE_OBJECT DeviceObject,
67: IN PIRP Irp,
68: IN ULONG MaximumBytes
69: );
70:
71: VOID
72: ScsiTapeError(
73: PDEVICE_OBJECT DeviceObject,
74: PSCSI_REQUEST_BLOCK Srb,
75: NTSTATUS *Status,
76: BOOLEAN *Retry
77: );
78:
79: NTSTATUS
80: ScsiTapeIoCompleteAssociated(
81: IN PDEVICE_OBJECT DeviceObject,
82: IN PIRP Irp,
83: IN PVOID Context
84: );
85:
86: #ifdef ALLOC_PRAGMA
87: #pragma alloc_text(init, DriverEntry)
88: #pragma alloc_text(init, FindScsiTapes)
89: #pragma alloc_text(init, CreateTapeDeviceObject)
90: #pragma alloc_text(init, UpdateTapeInformationInRegistry)
91: #endif
92:
93: //
94: // Start of code
95: //
96:
97:
98: NTSTATUS
99: DriverEntry(
100: IN PDRIVER_OBJECT DriverObject,
101: IN PUNICODE_STRING RegistryPath
102: )
103:
104: /*++
105:
106: Routine Description:
107:
108: This is the system initialization entry point for installable drivers.
109:
110: Arguments:
111:
112: DriverObject
113:
114: Return Value:
115:
116: NT Status
117:
118: --*/
119:
120: {
121: ULONG portNumber = 0;
122: PDEVICE_OBJECT portDeviceObject;
123: NTSTATUS status;
124: STRING deviceNameString;
125: UNICODE_STRING unicodeDeviceName;
126: PFILE_OBJECT fileObject;
127: CCHAR deviceNameBuffer[256];
128: BOOLEAN tapeDeviceFound = FALSE;
129:
130: DebugPrint((1,"\n\nSCSI Tape Class Driver\n"));
131:
132: //
133: // Update driver object with entry points.
134: //
135:
136: DriverObject->MajorFunction[IRP_MJ_READ] = ScsiTapeReadWrite;
137: DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiTapeReadWrite;
138: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiTapeDeviceControl;
139: DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiTapeCreate;
140:
141: //
142: // Open port driver controller device objects by name.
143: //
144:
145: do {
146:
147: sprintf(deviceNameBuffer, "\\Device\\ScsiPort%d", portNumber);
148:
149: DebugPrint((2, "ScsiTapeInitialize: Open Port %s\n", deviceNameBuffer));
150:
151: RtlInitString(&deviceNameString, deviceNameBuffer);
152:
153: status = RtlAnsiStringToUnicodeString(&unicodeDeviceName,
154: &deviceNameString,
155: TRUE
156: );
157:
158: ASSERT(NT_SUCCESS(status));
159:
160:
161: status = IoGetDeviceObjectPointer(&unicodeDeviceName,
162: FILE_READ_ATTRIBUTES,
163: &fileObject,
164: &portDeviceObject);
165:
166: if (NT_SUCCESS(status)) {
167:
168: if (FindScsiTapes(DriverObject, portDeviceObject, portNumber)) {
169: tapeDeviceFound = TRUE;
170: }
171: }
172:
173: //
174: // Check next SCSI adapter.
175: //
176:
177: portNumber++;
178:
179: } while(NT_SUCCESS(status));
180:
181: return(tapeDeviceFound ? STATUS_SUCCESS: STATUS_NO_SUCH_DEVICE);
182:
183: } // end DriverEntry()
184:
185:
186: BOOLEAN
187: FindScsiTapes(
188: IN PDRIVER_OBJECT DriverObject,
189: IN PDEVICE_OBJECT PortDeviceObject,
190: IN ULONG PortNumber
191: )
192:
193: /*++
194:
195: Routine Description:
196:
197: Call into port driver to get configuration information to find
198: tape devices.
199:
200: Arguments:
201:
202: DriverObject
203: DeviceObject - Port driver device object.
204:
205: Return Value:
206:
207: TRUE if tape device(s) found.
208:
209: --*/
210:
211: {
212: PIO_SCSI_CAPABILITIES portCapabilities;
213: PULONG tapeCount;
214: PCHAR buffer;
215: PSCSI_INQUIRY_DATA lunInfo;
216: PSCSI_ADAPTER_BUS_INFO adapterInfo;
217: PINQUIRYDATA inquiryData;
218: PCONFIGURATION_INFORMATION configInfo;
219: NTSTATUS status;
220: ULONG scsiBus;
221: BOOLEAN tapeDeviceFound = FALSE;
222:
223: //
224: // Call port driver to get adapter capabilities.
225: //
226:
227: status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
228:
229: if (!NT_SUCCESS(status)) {
230: DebugPrint((1, "FindScsiTapes: ScsiClassGetCabilities failed\n"));
231:
232: }
233:
234: //
235: // Call port driver to get inquiry information to find disks.
236: //
237:
238: status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
239:
240: if (!NT_SUCCESS(status)) {
241: DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
242: return FALSE;
243: }
244:
245: configInfo = IoGetConfigurationInformation();
246:
247: tapeCount = &configInfo->TapeCount;
248:
249: adapterInfo = (PVOID) buffer;
250:
251: //
252: // For each SCSI bus this adapter supports ...
253: //
254:
255: for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
256:
257: //
258: // Get the SCSI bus scan data for this bus.
259: //
260:
261: lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
262:
263: //
264: // Search list for unclaimed disk devices.
265: //
266:
267: while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
268:
269: inquiryData = (PVOID)lunInfo->InquiryData;
270:
271: DebugPrint((3,
272: "FindScsiTapes: Inquiry data at %lx\n",
273: inquiryData));
274:
275: if ((inquiryData->DeviceType == SEQUENTIAL_ACCESS_DEVICE) &&
276: (!lunInfo->DeviceClaimed)) {
277:
278: if (TapeVerifyInquiry(lunInfo) == TRUE) {
279:
280: status = CreateTapeDeviceObject(DriverObject,
281: tapeCount,
282: portCapabilities,
283: lunInfo,
284: PortDeviceObject,
285: PortNumber);
286:
287: if (NT_SUCCESS(status)) {
288:
289: tapeDeviceFound = TRUE;
290:
291: //
292: // Increment tape count
293: //
294:
295: (*tapeCount)++;
296:
297: }
298: }
299: }
300:
301: //
302: // Get next LunInfo.
303: //
304:
305: if (lunInfo->NextInquiryDataOffset == 0) {
306: break;
307: }
308:
309: lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
310:
311: }
312: }
313:
314: ExFreePool(buffer);
315: return tapeDeviceFound;
316:
317: } // end FindScsiTapes()
318:
319:
320: VOID
321: UpdateTapeInformationInRegistry(
322: IN PDEVICE_OBJECT DeviceObject,
323: IN PSCSI_INQUIRY_DATA ScsiInquiryData,
324: IN ULONG PortNumber,
325: IN ULONG TapeNumber
326: )
327:
328: /*++
329:
330: Routine Description:
331:
332: This routine has knowledge about the layout of the device map information
333: in the registry. It will update this information to include a value
334: entry specifying the dos device name that is assumed to get assigned
335: to this NT device name. For more information on this assigning of the
336: dos device name look in the drive support routine in the hal that assigns
337: all dos names. Since most version of tape firmware do not work and most
338: vendor did not bother to follow the specification the entire inquiry
339: information must also be stored in the registry so than someone can
340: figure out the firmware version.
341:
342: Arguments:
343:
344: DeviceObject - A pointer to the device object for the tape device.
345:
346: ScsiInquiryData - a pointer to the scsi inquiry data structure defined in
347: ntddscsi.h
348:
349: Return Value:
350:
351: None
352:
353: --*/
354:
355: {
356: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
357: NTSTATUS status;
358: OBJECT_ATTRIBUTES objectAttributes;
359: PUCHAR buffer;
360: STRING string;
361: UNICODE_STRING unicodeName;
362: UNICODE_STRING unicodeData;
363: HANDLE targetKey;
364: PINQUIRYDATA dataBuffer;
365: SCSI_REQUEST_BLOCK srb;
366: ULONG length;
367: PCDB cdb;
368:
369: buffer = ExAllocatePool(NonPagedPool, 1024);
370: dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, MAXIMUM_TAPE_INQUIRY_DATA);
371: if (buffer == NULL || dataBuffer == NULL) {
372:
373: if (buffer != NULL) {
374: ExFreePool(buffer);
375: }
376:
377: //
378: // There is not return value for this. Since this is done at
379: // claim device time (currently only system initialization) getting
380: // the registry information correct will be the least of the worries.
381: //
382:
383: return;
384: }
385: sprintf(buffer,
386: "\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi\\Scsi Port %d\\Scsi Bus %d\\Target Id %d\\Logical Unit Id %d",
387: PortNumber,
388: ScsiInquiryData->PathId,
389: ScsiInquiryData->TargetId,
390: ScsiInquiryData->Lun);
391:
392: RtlInitString(&string, buffer);
393: status = RtlAnsiStringToUnicodeString(&unicodeName,
394: &string,
395: TRUE);
396: if (NT_SUCCESS(status)) {
397:
398: //
399: // Open the registry key for the scsi information for this
400: // scsibus, target, lun.
401: //
402:
403: InitializeObjectAttributes(&objectAttributes,
404: &unicodeName,
405: OBJ_CASE_INSENSITIVE,
406: NULL,
407: NULL);
408: status = ZwOpenKey(&targetKey,
409: KEY_READ | KEY_WRITE,
410: &objectAttributes);
411: RtlFreeUnicodeString(&unicodeName);
412:
413: if (NT_SUCCESS(status)) {
414:
415: //
416: // Now construct and attempt to create the registry value
417: // specifying the device name in the appropriate place in the
418: // device map.
419: //
420:
421: RtlInitUnicodeString(&unicodeName, L"DeviceName");
422:
423: sprintf(buffer, "Tape%d", TapeNumber);
424: RtlInitString(&string, buffer);
425: RtlAnsiStringToUnicodeString(&unicodeData,
426: &string,
427: TRUE);
428: if (NT_SUCCESS(status)) {
429: status = ZwSetValueKey(targetKey,
430: &unicodeName,
431: 0,
432: REG_SZ,
433: unicodeData.Buffer,
434: unicodeData.Length);
435: RtlFreeUnicodeString(&unicodeData);
436: }
437:
438: //
439: // Now get the full inquiry information for the device.
440: //
441:
442: RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
443:
444: //
445: // Set timeout value.
446: //
447:
448: srb.TimeOutValue = 2;
449:
450: srb.CdbLength = 6;
451:
452: cdb = (PCDB)srb.Cdb;
453:
454: //
455: // Set CDB operation code.
456: //
457:
458: cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
459:
460: //
461: // Set CDB LUN.
462: //
463:
464: cdb->CDB6INQUIRY.LogicalUnitNumber = deviceExtension->Lun;
465:
466: //
467: // Set allocation length to inquiry data buffer size.
468: //
469:
470: cdb->CDB6INQUIRY.AllocationLength = MAXIMUM_TAPE_INQUIRY_DATA;
471:
472: status = ScsiClassSendSrbSynchronous(DeviceObject,
473: &srb,
474: dataBuffer,
475: MAXIMUM_TAPE_INQUIRY_DATA,
476: FALSE);
477:
478: if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_SUCCESS ||
479: SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
480:
481: //
482: // Updated the length actually transfered.
483: //
484:
485: length = dataBuffer->AdditionalLength +
486: FIELD_OFFSET(INQUIRYDATA, Reserved);
487:
488: if (length > srb.DataTransferLength) {
489: length = srb.DataTransferLength;
490: }
491:
492: RtlInitUnicodeString(&unicodeName, L"InquiryData");
493:
494: status = ZwSetValueKey(targetKey,
495: &unicodeName,
496: 0,
497: REG_BINARY,
498: dataBuffer,
499: length);
500:
501: }
502:
503: ZwClose(targetKey);
504: }
505: }
506:
507: ExFreePool(buffer);
508: ExFreePool(dataBuffer);
509: }
510:
511:
512: NTSTATUS
513: CreateTapeDeviceObject(
514: IN PDRIVER_OBJECT DriverObject,
515: IN PULONG DeviceCount,
516: IN PIO_SCSI_CAPABILITIES PortCapabilities,
517: IN PSCSI_INQUIRY_DATA LunInfo,
518: IN PDEVICE_OBJECT PortDeviceObject,
519: IN ULONG PortNumber
520: )
521:
522: /*++
523:
524: Routine Description:
525:
526: This routine creates an object for the device and then searches
527: the device for partitions and creates an object for each partition.
528:
529: Arguments:
530:
531: DriverObject - Pointer to driver object created by system.
532: DeviceCount - Pointer to number of previously installed tapes.
533: PortCapabilities - Pointer to port capabilities structure
534: LunInfo - Pointer to Logical Unit Information structure.
535: PortDeviceObject - Pointer to device object of SCSI adapter.
536: PortNumber - Number of the SCSI port.
537:
538: Return Value:
539:
540: NTSTATUS
541:
542: --*/
543:
544: {
545: CCHAR deviceNameBuffer[64];
546: CCHAR dosNameBuffer[64];
547: STRING deviceNameString;
548: UNICODE_STRING unicodeString;
549: NTSTATUS status;
550: PDEVICE_OBJECT deviceObject;
551: ULONG requiredStackSize;
552: PDEVICE_EXTENSION deviceExtension;
553: PTAPE_DATA tapeData;
554: UCHAR pathId = LunInfo->PathId;
555: UCHAR targetId = LunInfo->TargetId;
556: UCHAR lun = LunInfo->Lun;
557: PVOID senseData;
558: STRING dosString;
559: UNICODE_STRING dosUnicodeString;
560:
561: DebugPrint((3,"CreateDeviceObject: Enter routine\n"));
562:
563: //
564: // Create device object for this device.
565: //
566:
567: sprintf(deviceNameBuffer,
568: "\\Device\\Tape%d",
569: *DeviceCount);
570:
571: RtlInitString(&deviceNameString,
572: deviceNameBuffer);
573:
574: DebugPrint((2,"CreateDeviceObjects: Create device object %s\n",
575: deviceNameBuffer));
576:
577: status = RtlAnsiStringToUnicodeString(&unicodeString,
578: &deviceNameString,
579: TRUE);
580:
581: ASSERT(NT_SUCCESS(status));
582:
583: status = IoCreateDevice(DriverObject,
584: DEVICE_EXTENSION_SIZE,
585: &unicodeString,
586: FILE_DEVICE_TAPE,
587: FILE_REMOVABLE_MEDIA,
588: FALSE,
589: &deviceObject);
590:
591: if (!NT_SUCCESS(status)) {
592: DebugPrint((1,"CreateDeviceObjects: Can not create device %s\n",
593: deviceNameBuffer));
594:
595: return status;
596: }
597:
598: //
599: // Claim the device.
600: //
601:
602: status = ScsiClassClaimDevice(
603: PortDeviceObject,
604: LunInfo,
605: FALSE,
606: &PortDeviceObject
607: );
608:
609: if (!NT_SUCCESS(status)) {
610: IoDeleteDevice(deviceObject);
611: return(status);
612: }
613:
614: //
615: // Create the dos port driver name.
616: //
617:
618: sprintf(dosNameBuffer,
619: "\\DosDevices\\TAPE%d",
620: *DeviceCount);
621:
622: RtlInitString(&dosString, dosNameBuffer);
623:
624: status = RtlAnsiStringToUnicodeString(&dosUnicodeString,
625: &dosString,
626: TRUE);
627:
628: if(!NT_SUCCESS(status)) {
629: dosUnicodeString.Buffer = NULL;
630: }
631:
632: if (dosUnicodeString.Buffer != NULL && unicodeString.Buffer != NULL) {
633: IoAssignArcName(&dosUnicodeString, &unicodeString);
634: }
635:
636: if (dosUnicodeString.Buffer != NULL) {
637: RtlFreeUnicodeString(&dosUnicodeString);
638: }
639:
640: if (unicodeString.Buffer != NULL ) {
641: RtlFreeUnicodeString(&unicodeString);
642: }
643:
644: //
645: // Indicate that IRPs should include MDLs.
646: //
647:
648: deviceObject->Flags |= DO_DIRECT_IO;
649:
650: //
651: // Set up required stack size in device object.
652: //
653:
654: deviceExtension = deviceObject->DeviceExtension;
655:
656: requiredStackSize = PortDeviceObject->StackSize + 1;
657:
658: deviceExtension->PortDeviceObject = PortDeviceObject;
659:
660: //
661: // Allocate spinlock for split request completion.
662: //
663:
664: KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
665:
666: deviceObject->StackSize = (CCHAR)requiredStackSize;
667:
668: //
669: // Save address of port driver capabilities.
670: //
671:
672: deviceExtension->PortCapabilities = PortCapabilities;
673:
674: //
675: // Save Current Partition number and inquiry data.
676: //
677:
678: tapeData = (PTAPE_DATA )(deviceExtension + 1 );
679:
680: tapeData->CurrentPartition = 0;
681:
682: tapeData->InquiryData = LunInfo;
683:
684: //
685: // Disable synchronous transfer for tape requests.
686: //
687:
688: deviceExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
689:
690: //
691: // Allocate request sense buffer.
692: //
693:
694: senseData = ExAllocatePool(NonPagedPoolCacheAligned,
695: SENSE_BUFFER_SIZE);
696:
697: if (senseData == NULL) {
698:
699: //
700: // The buffer could not be allocated.
701: //
702:
703: IoDeleteDevice(deviceObject);
704:
705: return(STATUS_INSUFFICIENT_RESOURCES);
706: }
707:
708: //
709: // Set the sense data pointer in the device extension.
710: //
711:
712: deviceExtension->SenseData = senseData;
713:
714: //
715: // TargetId/LUN describes a device location on the SCSI bus.
716: // This information comes from the inquiry buffer.
717: //
718:
719: deviceExtension->PortNumber = (UCHAR) PortNumber;
720: deviceExtension->PathId = pathId;
721: deviceExtension->TargetId = targetId;
722: deviceExtension->Lun = lun;
723:
724: //
725: // Set timeout value in seconds.
726: //
727:
728: deviceExtension->TimeOutValue = 180;
729:
730: //
731: // Back pointer to device object.
732: //
733:
734: deviceExtension->DeviceObject = deviceObject;
735:
736: //
737: // Allocate buffer for drive geometry.
738: //
739:
740: deviceExtension->DiskGeometry =
741: ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY));
742:
743: if (!deviceExtension->DiskGeometry) {
744:
745: ExFreePool(senseData);
746:
747: //
748: // Release device.
749: //
750:
751: ScsiClassClaimDevice(PortDeviceObject,
752: LunInfo,
753: TRUE,
754: &PortDeviceObject);
755:
756:
757: IoDeleteDevice(deviceObject);
758: return(STATUS_INSUFFICIENT_RESOURCES);
759: }
760:
761: //
762: // Initialize fixed block size of 512 bytes.
763: //
764:
765: deviceExtension->DiskGeometry->BytesPerSector = 512;
766: deviceExtension->SectorShift = 9;
767:
768: //
769: // Set tape error handler.
770: //
771:
772: deviceExtension->ClassError = ScsiTapeError;
773:
774: //
775: // Add tape device number to registry
776: //
777:
778: UpdateTapeInformationInRegistry(deviceObject,
779: LunInfo,
780: PortNumber,
781: *DeviceCount);
782:
783: return STATUS_SUCCESS;
784:
785: } // end CreateTapeDeviceObject()
786:
787:
788: NTSTATUS
789: ScsiTapeReadWrite(
790: IN PDEVICE_OBJECT DeviceObject,
791: IN PIRP Irp
792: )
793:
794: /*++
795:
796: Routine Description:
797:
798: This is the tape class driver IO handler routine. It is the system entry
799: point for read and write requests. The number of bytes in the request are
800: checked against the maximum byte counts that the adapter supports and
801: requests are broken up into smaller sizes if necessary. Then the
802: device-specific handler is called.
803:
804: Arguments:
805:
806: DeviceObject
807: Irp - IO request
808:
809: Return Value:
810:
811: NT Status
812:
813: --*/
814:
815: {
816: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
817: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
818: ULONG transferPages;
819: ULONG transferByteCount =
820: currentIrpStack->Parameters.Read.Length;
821: LARGE_INTEGER startingOffset =
822: currentIrpStack->Parameters.Read.ByteOffset;
823: ULONG maximumTransferLength =
824: deviceExtension->PortCapabilities->MaximumTransferLength;
825: NTSTATUS status;
826:
827: DebugPrint((3,"ScsiTapeRead: Enter routine\n"));
828:
829: if (DeviceObject->Flags & DO_VERIFY_VOLUME &&
830: !(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
831:
832: //
833: // if DO_VERIFY_VOLUME bit is set
834: // in device object flags, fail request.
835: //
836:
837: DebugPrint((3,"ScsiTapeRead: Volume verfication needed\n"));
838:
839: Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
840: Irp->IoStatus.Information = 0;
841:
842: IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
843:
844: IoCompleteRequest(Irp, 0);
845:
846: return STATUS_VERIFY_REQUIRED;
847: }
848:
849: //
850: // Calculate number of pages in this transfer.
851: //
852:
853: transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
854: MmGetMdlVirtualAddress(Irp->MdlAddress),
855: currentIrpStack->Parameters.Read.Length);
856:
857: //
858: // Check if request length is greater than the maximum number of
859: // bytes that the hardware can transfer.
860: //
861:
862: if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
863: transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
864:
865: DebugPrint((2,"ScsiTapeRead: Request greater than maximum\n"));
866: DebugPrint((2,"ScsiTapeRead: Maximum is %lx\n",
867: maximumTransferLength));
868: DebugPrint((2,"ScsiTapeRead: Byte count is %lx\n",
869: currentIrpStack->Parameters.Read.Length));
870:
871: transferPages =
872: deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
873:
874: if (maximumTransferLength > transferPages << PAGE_SHIFT ) {
875: maximumTransferLength = transferPages << PAGE_SHIFT;
876: }
877:
878: //
879: // Check that maximum transfer size is not zero.
880: //
881:
882: if (maximumTransferLength == 0) {
883: maximumTransferLength = PAGE_SIZE;
884: }
885:
886: //
887: // Mark IRP with status pending.
888: //
889:
890: IoMarkIrpPending(Irp);
891:
892: //
893: // Request greater than port driver maximum.
894: // Break up into smaller routines.
895: //
896:
897: SplitTapeRequest(DeviceObject, Irp, maximumTransferLength);
898:
899:
900: return STATUS_PENDING;
901: }
902:
903: //
904: // Build SRB and CDB for this IRP.
905: //
906:
907: status = TapeReadWrite(DeviceObject, Irp);
908:
909: if (status == STATUS_PENDING) {
910:
911: //
912: // Return the results of the call to the port driver.
913: //
914:
915: return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
916:
917: } else {
918:
919: //
920: // Complete request.
921: //
922:
923: IoCompleteRequest(Irp, 0);
924:
925: return status;
926: }
927:
928: } // end ScsiTapeReadWrite()
929:
930:
931: NTSTATUS
932: ScsiTapeDeviceControl(
933: IN PDEVICE_OBJECT DeviceObject,
934: IN PIRP Irp
935: )
936:
937: /*++
938:
939: Routine Description:
940:
941: This routine is the dispatcher for device control requests. It
942: looks at the IOCTL code and calls the appropriate tape device
943: routine.
944:
945: Arguments:
946:
947: DeviceObject
948: Irp - Request packet
949:
950: Return Value:
951:
952: --*/
953:
954: {
955: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
956: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
957: NTSTATUS status;
958: BOOLEAN retried = FALSE;
959:
960: DebugPrint((3,"ScsiTapeDeviceControl: Enter routine\n"));
961:
962: switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
963:
964: case IOCTL_TAPE_GET_DRIVE_PARAMS:
965:
966: //
967: // Validate buffer length.
968: //
969:
970: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
971: sizeof(TAPE_GET_DRIVE_PARAMETERS)) {
972:
973: status = STATUS_INFO_LENGTH_MISMATCH;
974: break;
975: }
976:
977: status = TapeGetDriveParameters(DeviceObject, Irp);
978: break;
979:
980: case IOCTL_TAPE_SET_DRIVE_PARAMS:
981:
982: //
983: // Validate buffer length.
984: //
985:
986: if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
987: sizeof(TAPE_SET_DRIVE_PARAMETERS)) {
988:
989: status = STATUS_INFO_LENGTH_MISMATCH;
990: break;
991: }
992:
993: status = TapeSetDriveParameters(DeviceObject, Irp);
994: break;
995:
996: case IOCTL_TAPE_GET_MEDIA_PARAMS:
997:
998: //
999: // Validate buffer length.
1000: //
1001:
1002: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1003: sizeof(TAPE_GET_MEDIA_PARAMETERS)) {
1004:
1005: status = STATUS_INFO_LENGTH_MISMATCH;
1006: break;
1007: }
1008:
1009: status = TapeGetMediaParameters(DeviceObject, Irp);
1010: break;
1011:
1012: case IOCTL_TAPE_SET_MEDIA_PARAMS:
1013: {
1014: PTAPE_SET_MEDIA_PARAMETERS tapeSetMediaParams =
1015: Irp->AssociatedIrp.SystemBuffer;
1016: ULONG sectorShift;
1017:
1018: //
1019: // Validate buffer length.
1020: //
1021:
1022: if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1023: sizeof(TAPE_SET_MEDIA_PARAMETERS)) {
1024:
1025: status = STATUS_INFO_LENGTH_MISMATCH;
1026: break;
1027: }
1028:
1029: //
1030: // Make sure the block size is a power of 2.
1031: //
1032:
1033: WHICH_BIT(tapeSetMediaParams->BlockSize, sectorShift);
1034:
1035: if (tapeSetMediaParams->BlockSize != (ULONG)(1 << sectorShift)) {
1036:
1037: status = STATUS_INVALID_PARAMETER;
1038: break;
1039: }
1040:
1041: status = TapeSetMediaParameters(DeviceObject, Irp);
1042:
1043: if (NT_SUCCESS(status)) {
1044:
1045: //
1046: // Set the block size in the device object.
1047: //
1048:
1049: deviceExtension->DiskGeometry->BytesPerSector =
1050: tapeSetMediaParams->BlockSize;
1051: deviceExtension->SectorShift = (UCHAR)sectorShift;
1052:
1053: }
1054:
1055: break;
1056:
1057: }
1058:
1059: case IOCTL_TAPE_CREATE_PARTITION:
1060:
1061: //
1062: // Validate buffer length.
1063: //
1064:
1065: if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1066: sizeof(TAPE_CREATE_PARTITION)) {
1067:
1068: status = STATUS_INFO_LENGTH_MISMATCH;
1069: break;
1070: }
1071:
1072: status = TapeCreatePartition (DeviceObject, Irp);
1073: break;
1074:
1075: case IOCTL_TAPE_ERASE:
1076:
1077: //
1078: // Validate buffer length.
1079: //
1080:
1081: if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1082: sizeof(TAPE_ERASE)) {
1083:
1084: status = STATUS_INFO_LENGTH_MISMATCH;
1085: break;
1086: }
1087:
1088: status = TapeErase(DeviceObject, Irp);
1089: break;
1090:
1091: case IOCTL_TAPE_PREPARE:
1092:
1093: //
1094: // Validate buffer length.
1095: //
1096:
1097: if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1098: sizeof(TAPE_PREPARE)) {
1099:
1100: status = STATUS_INFO_LENGTH_MISMATCH;
1101: break;
1102: }
1103:
1104: status = TapePrepare(DeviceObject, Irp);
1105: break;
1106:
1107: case IOCTL_TAPE_WRITE_MARKS:
1108:
1109: //
1110: // Validate buffer length.
1111: //
1112:
1113: if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1114: sizeof(TAPE_WRITE_MARKS)) {
1115:
1116: status = STATUS_INFO_LENGTH_MISMATCH;
1117: break;
1118: }
1119:
1120: status = TapeWriteMarks(DeviceObject, Irp);
1121: break;
1122:
1123: case IOCTL_TAPE_GET_POSITION:
1124:
1125: //
1126: // Validate buffer length.
1127: //
1128:
1129: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1130: sizeof(TAPE_GET_POSITION)) {
1131:
1132: status = STATUS_INFO_LENGTH_MISMATCH;
1133: break;
1134: }
1135:
1136: status = TapeGetPosition(DeviceObject, Irp);
1137: break;
1138:
1139: case IOCTL_TAPE_SET_POSITION:
1140:
1141: //
1142: // Validate buffer length.
1143: //
1144:
1145: if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1146: sizeof(TAPE_SET_POSITION)) {
1147:
1148: status = STATUS_INFO_LENGTH_MISMATCH;
1149: break;
1150: }
1151:
1152: status = TapeSetPosition(DeviceObject, Irp);
1153: break;
1154:
1155: case IOCTL_TAPE_GET_STATUS:
1156:
1157: status = TapeGetStatus (DeviceObject, Irp);
1158: break;
1159:
1160: default:
1161:
1162: //
1163: // Pass the request to the common device control routine.
1164: //
1165:
1166: return(ScsiClassDeviceControl(DeviceObject, Irp));
1167:
1168: } // end switch()
1169:
1170: ASSERT(status != STATUS_VERIFY_REQUIRED);
1171:
1172: //
1173: // Complete the request.
1174: //
1175:
1176: Irp->IoStatus.Status = status;
1177: IoCompleteRequest(Irp, 2);
1178:
1179: return status;
1180:
1181: } // end ScsiScsiTapeDeviceControl()
1182:
1183:
1184: NTSTATUS
1185: ScsiTapeCreate (
1186: IN PDEVICE_OBJECT DeviceObject,
1187: IN PIRP Irp
1188: )
1189:
1190: /*++
1191:
1192: Routine Description:
1193:
1194: This routine handles CREATE/OPEN requests and does
1195: nothing more than return successful status.
1196:
1197: Arguments:
1198:
1199: DeviceObject
1200: Irp
1201:
1202: Return Value:
1203:
1204: NT Status
1205:
1206: --*/
1207:
1208: {
1209: UNREFERENCED_PARAMETER(DeviceObject);
1210:
1211: Irp->IoStatus.Status = STATUS_SUCCESS;
1212:
1213: IoCompleteRequest(Irp, 0);
1214:
1215: return STATUS_SUCCESS;
1216:
1217: } // end ScsiTapeCreate()
1218:
1219:
1220: VOID
1221: SplitTapeRequest(
1222: IN PDEVICE_OBJECT DeviceObject,
1223: IN PIRP Irp,
1224: IN ULONG MaximumBytes
1225: )
1226:
1227: /*++
1228:
1229: Routine Description:
1230:
1231: Break request into smaller requests.
1232: Each new request will be the maximum transfer
1233: size that the port driver can handle or if it
1234: is the final request, it may be the residual
1235: size.
1236:
1237: The number of IRPs required to process this
1238: request is written in the current stack of
1239: the original IRP. Then as each new IRP completes
1240: the count in the original IRP is decremented.
1241: When the count goes to zero, the original IRP
1242: is completed.
1243:
1244: Arguments:
1245:
1246: DeviceObject - Pointer to the device object
1247: Irp - Pointer to Irp
1248:
1249: Return Value:
1250:
1251: None.
1252:
1253: --*/
1254:
1255: {
1256: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1257: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1258: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
1259: ULONG irpCount;
1260: ULONG transferByteCount =
1261: currentIrpStack->Parameters.Read.Length;
1262: PSCSI_REQUEST_BLOCK srb;
1263: LARGE_INTEGER startingOffset =
1264: currentIrpStack->Parameters.Read.ByteOffset;
1265: ULONG dataLength = MaximumBytes;
1266: PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1267: INTERLOCKED_RESULT remainingIrps;
1268: BOOLEAN completeOriginalIrp = FALSE;
1269: NTSTATUS status;
1270: ULONG i;
1271:
1272: //
1273: // Caluculate number of requests to break this IRP into.
1274: //
1275:
1276: irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes;
1277:
1278: DebugPrint((2, "SplitTapeRequest: Requires %d IRPs\n", irpCount));
1279:
1280: DebugPrint((2, "SplitTapeRequest: Original IRP %lx\n", Irp));
1281:
1282: //
1283: // If all partial transfers complete successfully then
1284: // the status is already set up.
1285: // Failing partial transfer IRP will set status to
1286: // error and bytes transferred to 0 during IoCompletion.
1287: // Setting bytes transferred to 0 if an IRP
1288: // fails allows asynchronous partial transfers. This is an
1289: // optimization for the successful case. As the irps complete
1290: // with partital or full transfers they will update the bytes
1291: // transfered. This is handle as a special case since a read or
1292: // write can succeed but on part of the data is transfered.
1293: //
1294:
1295: Irp->IoStatus.Status = STATUS_SUCCESS;
1296:
1297: //
1298: // Save number of IRPs to complete count on current stack
1299: // of original IRP.
1300: //
1301:
1302: nextIrpStack->Parameters.Others.Argument1 = (PVOID)irpCount;
1303:
1304: for (i = 0; i < irpCount; i++) {
1305:
1306: PIRP newIrp;
1307: PIO_STACK_LOCATION newIrpStack;
1308:
1309: //
1310: // Allocate new IRP.
1311: //
1312:
1313: newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1314:
1315: if (newIrp == NULL) {
1316:
1317: DebugPrint((1,"SplitTapeRequest: Can't allocate Irp\n"));
1318:
1319: //
1320: // Decrement count of outstanding partial requests.
1321: //
1322:
1323: remainingIrps = ExInterlockedDecrementLong(
1324: (PLONG)&nextIrpStack->Parameters.Others.Argument1,
1325: &deviceExtension->SplitRequestSpinLock);
1326:
1327: //
1328: // Check if any outstanding IRPs.
1329: //
1330:
1331: if (remainingIrps == ResultZero) {
1332: completeOriginalIrp = TRUE;
1333: }
1334:
1335: //
1336: // Update original IRP with failing status.
1337: //
1338:
1339: Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1340: Irp->IoStatus.Information = 0;
1341:
1342: //
1343: // Keep going with this request as outstanding partials
1344: // may be in progress.
1345: //
1346:
1347: goto KeepGoing;
1348: }
1349:
1350: DebugPrint((2, "SplitTapeRequest: New IRP %lx\n", newIrp));
1351:
1352: //
1353: // Write MDL address to new IRP.
1354: // In the port driver the SRB data length
1355: // field is used as an offset into the MDL,
1356: // so the same MDL can be used for each partial
1357: // transfer. This saves having to build a new
1358: // MDL for each partial transfer.
1359: //
1360:
1361: newIrp->MdlAddress = Irp->MdlAddress;
1362:
1363: //
1364: // At this point there is no current stack.
1365: // IoSetNextIrpStackLocation will make the
1366: // first stack location the current stack
1367: // so that the SRB address can be written
1368: // there.
1369: //
1370:
1371: IoSetNextIrpStackLocation(newIrp);
1372:
1373: newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
1374:
1375: newIrpStack->MajorFunction = currentIrpStack->MajorFunction;
1376:
1377: newIrpStack->Parameters.Read.Length = dataLength;
1378: newIrpStack->Parameters.Read.ByteOffset = startingOffset;
1379:
1380: newIrpStack->DeviceObject = DeviceObject;
1381:
1382: //
1383: // Build SRB and CDB.
1384: //
1385:
1386: status = TapeReadWrite(DeviceObject, newIrp);
1387:
1388: if (!NT_SUCCESS(status)) {
1389:
1390: DebugPrint((1,"SplitTapeRequest: TapeReadWrite failed\n"));
1391:
1392: //
1393: // Decrement count of outstanding partial requests.
1394: //
1395:
1396: remainingIrps =ExInterlockedDecrementLong(
1397: (PLONG)&nextIrpStack->Parameters.Others.Argument1,
1398: &deviceExtension->SplitRequestSpinLock);
1399:
1400: //
1401: // Check if any outstanding IRPs.
1402: //
1403:
1404: if (remainingIrps == ResultZero) {
1405: completeOriginalIrp = TRUE;
1406: }
1407:
1408: //
1409: // Update original IRP with failing status.
1410: //
1411:
1412: Irp->IoStatus.Status = status;
1413: Irp->IoStatus.Information = 0;
1414:
1415: //
1416: // Deallocate this partial IRP.
1417: //
1418:
1419: IoFreeIrp(newIrp);
1420:
1421: //
1422: // Keep going with this request as outstanding partials
1423: // may be in progress.
1424: //
1425:
1426: goto KeepGoing;
1427: }
1428:
1429: //
1430: // Adjust SRB for this partial transfer.
1431: //
1432:
1433: newIrpStack = IoGetNextIrpStackLocation(newIrp);
1434:
1435: srb = newIrpStack->Parameters.Others.Argument1;
1436:
1437: srb->DataBuffer = dataBuffer;
1438:
1439: //
1440: // Write original IRP address to new IRP.
1441: //
1442:
1443: newIrp->AssociatedIrp.MasterIrp = Irp;
1444:
1445: //
1446: // Set the completion routine to ScsiTapeIoCompleteAssociated.
1447: //
1448:
1449: IoSetCompletionRoutine(newIrp,
1450: ScsiTapeIoCompleteAssociated,
1451: srb,
1452: TRUE,
1453: TRUE,
1454: TRUE);
1455:
1456: //
1457: // Call port driver with new request.
1458: //
1459:
1460: status = IoCallDriver(deviceExtension->PortDeviceObject, newIrp);
1461:
1462: if (!NT_SUCCESS(status)) {
1463:
1464: DebugPrint((1,"SplitTapeRequest: IoCallDriver returned error\n"));
1465:
1466: //
1467: // Decrement count of outstanding partial requests.
1468: //
1469:
1470: remainingIrps = ExInterlockedDecrementLong(
1471: (PLONG)&nextIrpStack->Parameters.Others.Argument1,
1472: &deviceExtension->SplitRequestSpinLock);
1473:
1474: //
1475: // Check if any outstanding IRPs.
1476: //
1477:
1478: if (remainingIrps == ResultZero) {
1479: completeOriginalIrp = TRUE;
1480: }
1481:
1482: //
1483: // Update original IRP with failing status.
1484: //
1485:
1486: Irp->IoStatus.Status = status;
1487: Irp->IoStatus.Information = 0;
1488:
1489: //
1490: // Deallocate this partial IRP.
1491: //
1492:
1493: IoFreeIrp(newIrp);
1494: }
1495:
1496: KeepGoing:
1497:
1498: //
1499: // Set up for next request.
1500: //
1501:
1502: dataBuffer = (PCHAR)dataBuffer + MaximumBytes;
1503:
1504: transferByteCount -= MaximumBytes;
1505:
1506: if (transferByteCount > MaximumBytes) {
1507:
1508: dataLength = MaximumBytes;
1509:
1510: } else {
1511:
1512: dataLength = transferByteCount;
1513: }
1514:
1515: //
1516: // Adjust disk byte offset.
1517: //
1518:
1519: startingOffset = RtlLargeIntegerAdd(startingOffset, RtlConvertUlongToLargeInteger(MaximumBytes));
1520: }
1521:
1522: //
1523: // Check if original IRP should be completed.
1524: //
1525:
1526: if (completeOriginalIrp) {
1527:
1528: IoCompleteRequest(Irp, 0);
1529: }
1530:
1531: return;
1532:
1533: } // end SplitTapeRequest()
1534:
1535:
1536: VOID
1537: ScsiTapeError(
1538: PDEVICE_OBJECT DeviceObject,
1539: PSCSI_REQUEST_BLOCK Srb,
1540: NTSTATUS *Status,
1541: BOOLEAN *Retry
1542: )
1543:
1544: /*++
1545:
1546: Routine Description:
1547:
1548: When a request completes with error, the routine ScsiClassInterpretSenseInfo is
1549: called to determine from the sense data whether the request should be
1550: retried and what NT status to set in the IRP. Then this routine is called
1551: for tape requests to handle tape-specific errors and update the nt status
1552: and retry boolean.
1553:
1554: Arguments:
1555:
1556: DeviceObject - Supplies a pointer to the device object.
1557:
1558: Srb - Supplies a pointer to the failing Srb.
1559:
1560: Status - NT Status used to set the IRP's completion status.
1561:
1562: Retry - Indicates that this request should be retried.
1563:
1564: Return Value:
1565:
1566: None.
1567:
1568: --*/
1569:
1570: {
1571: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1572: PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
1573: PIRP irp = Srb->OriginalRequest;
1574: ULONG residualBlocks;
1575: LONG length;
1576:
1577: //
1578: // Never retry tape requests.
1579: //
1580:
1581: *Retry = FALSE;
1582:
1583: //
1584: // Check that request sense buffer is valid.
1585: //
1586:
1587: if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
1588:
1589: switch (senseBuffer->SenseKey & 0xf) {
1590:
1591: case SCSI_SENSE_UNIT_ATTENTION:
1592:
1593: switch (senseBuffer->AdditionalSenseCode) {
1594:
1595: case SCSI_ADSENSE_MEDIUM_CHANGED:
1596: DebugPrint((1,
1597: "InterpretSenseInfo: Media changed\n"));
1598:
1599: *Status = STATUS_MEDIA_CHANGED;
1600:
1601: break;
1602:
1603: default:
1604: DebugPrint((1,
1605: "InterpretSenseInfo: Bus reset\n"));
1606:
1607: *Status = STATUS_BUS_RESET;
1608:
1609: break;
1610:
1611: }
1612:
1613: break;
1614:
1615: case SCSI_SENSE_RECOVERED_ERROR:
1616:
1617: //
1618: // Check other indicators
1619: //
1620:
1621: if (senseBuffer->FileMark) {
1622:
1623: switch (senseBuffer->AdditionalSenseCodeQualifier) {
1624:
1625: case SCSI_SENSEQ_SETMARK_DETECTED :
1626:
1627: DebugPrint((1,
1628: "InterpretSenseInfo: Setmark detected\n"));
1629:
1630: *Status = STATUS_SETMARK_DETECTED;
1631: break ;
1632:
1633: case SCSI_SENSEQ_FILEMARK_DETECTED :
1634: default:
1635:
1636: DebugPrint((1,
1637: "InterpretSenseInfo: Filemark detected\n"));
1638:
1639: *Status = STATUS_FILEMARK_DETECTED;
1640: break ;
1641:
1642: }
1643:
1644: } else if ( senseBuffer->EndOfMedia ) {
1645:
1646: switch( senseBuffer->AdditionalSenseCodeQualifier ) {
1647:
1648: case SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED :
1649:
1650: DebugPrint((1,
1651: "InterpretSenseInfo: Beginning of media detected\n"));
1652:
1653: *Status = STATUS_BEGINNING_OF_MEDIA;
1654: break ;
1655:
1656: case SCSI_SENSEQ_END_OF_MEDIA_DETECTED :
1657: default:
1658:
1659: DebugPrint((1,
1660: "InterpretSenseInfo: End of media detected\n"));
1661:
1662: *Status = STATUS_END_OF_MEDIA;
1663: break ;
1664:
1665: }
1666: }
1667:
1668: break;
1669:
1670: case SCSI_SENSE_NO_SENSE:
1671:
1672: //
1673: // Check other indicators
1674: //
1675:
1676: if (senseBuffer->FileMark) {
1677:
1678: switch( senseBuffer->AdditionalSenseCodeQualifier ) {
1679:
1680: case SCSI_SENSEQ_SETMARK_DETECTED :
1681:
1682: DebugPrint((1,
1683: "InterpretSenseInfo: Setmark detected\n"));
1684:
1685: *Status = STATUS_SETMARK_DETECTED;
1686: break ;
1687:
1688: case SCSI_SENSEQ_FILEMARK_DETECTED :
1689: default:
1690:
1691: DebugPrint((1,
1692: "InterpretSenseInfo: Filemark detected\n"));
1693:
1694: *Status = STATUS_FILEMARK_DETECTED;
1695: break ;
1696: }
1697:
1698: } else if (senseBuffer->EndOfMedia) {
1699:
1700: switch(senseBuffer->AdditionalSenseCodeQualifier) {
1701:
1702: case SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED :
1703:
1704: DebugPrint((1,
1705: "InterpretSenseInfo: Beginning of media detected\n"));
1706:
1707: *Status = STATUS_BEGINNING_OF_MEDIA;
1708: break ;
1709:
1710: case SCSI_SENSEQ_END_OF_MEDIA_DETECTED :
1711: default:
1712:
1713: DebugPrint((1,
1714: "InterpretSenseInfo: End of media detected\n"));
1715:
1716: *Status = STATUS_END_OF_MEDIA;
1717: break;
1718:
1719: }
1720: }
1721:
1722: break;
1723:
1724: case SCSI_SENSE_BLANK_CHECK:
1725:
1726: DebugPrint((1,
1727: "InterpretSenseInfo: Media blank check\n"));
1728:
1729: *Status = STATUS_NO_DATA_DETECTED;
1730:
1731:
1732: break;
1733:
1734: case SCSI_SENSE_VOL_OVERFLOW:
1735:
1736: DebugPrint((1,
1737: "InterpretSenseInfo: End of Media Overflow\n"));
1738:
1739: *Status = STATUS_EOM_OVERFLOW;
1740:
1741:
1742: break;
1743:
1744: case SCSI_SENSE_NOT_READY:
1745:
1746: switch (senseBuffer->AdditionalSenseCode) {
1747:
1748: case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
1749:
1750: DebugPrint((1,
1751: "InterpretSenseInfo:"
1752: " No Media in device.\n"));
1753: *Status = STATUS_NO_MEDIA;
1754: break;
1755: }
1756:
1757: break;
1758:
1759: } // end switch
1760:
1761: //
1762: // Check if a filemark or setmark was encountered,
1763: // or an end-of-media or no-data condition exists.
1764: //
1765:
1766: if (NT_WARNING(*Status) &&
1767: (Srb->Cdb[0] == SCSIOP_WRITE6 || Srb->Cdb[0] == SCSIOP_READ6)) {
1768:
1769: //
1770: // Not all bytes were transfered. Update information field with
1771: // number of bytes transfered from sense buffer.
1772: //
1773:
1774: if (senseBuffer->Valid) {
1775: REVERSE_BYTES((PFOUR_BYTE)&residualBlocks,
1776: (PFOUR_BYTE)senseBuffer->Information);
1777: } else {
1778: residualBlocks = 0;
1779: }
1780:
1781: length = ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLenLSB;
1782: length |= ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLen << 8;
1783: length |= ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLenMSB << 16;
1784:
1785: length -= residualBlocks;
1786:
1787: if (length < 0) {
1788:
1789: length = 0;
1790: *Status = STATUS_IO_DEVICE_ERROR;
1791: }
1792:
1793:
1794: length *= deviceExtension->DiskGeometry->BytesPerSector;
1795:
1796: //
1797: // If the miniport indicates fewer bytes were transfered then
1798: // use that value.
1799: //
1800:
1801: if ((ULONG) length > Srb->DataTransferLength) {
1802: length = (LONG) Srb->DataTransferLength;
1803: DebugPrint((1,"ScsiTapeError: Calculated length wronge using miniport length. \n"));
1804:
1805: }
1806:
1807: irp->IoStatus.Information = length;
1808:
1809: DebugPrint((1,"ScsiTapeError: Transfer Count: %lx\n", Srb->DataTransferLength));
1810: DebugPrint((1," Residual Bytes: %lx\n", residualBlocks * deviceExtension->DiskGeometry->BytesPerSector));
1811: DebugPrint((1," Irp IoStatus Information = %lx\n", irp->IoStatus.Information));
1812: }
1813:
1814: }
1815:
1816: //
1817: // Call tape device specific error handler.
1818: //
1819:
1820: TapeError(DeviceObject->DeviceExtension,
1821: Srb,
1822: Status,
1823: Retry);
1824:
1825: return;
1826:
1827: } // end ScsiTapeError()
1828:
1829: NTSTATUS
1830: ScsiTapeIoCompleteAssociated(
1831: IN PDEVICE_OBJECT DeviceObject,
1832: IN PIRP Irp,
1833: IN PVOID Context
1834: )
1835:
1836: /*++
1837:
1838: Routine Description:
1839:
1840: This routine executes when the port driver has completed a request.
1841: It looks at the SRB status in the completing SRB and if not success
1842: it checks for valid request sense buffer information. If valid, the
1843: info is used to update status with more precise message of type of
1844: error. This routine deallocates the SRB. This routine is used for
1845: requests which were build by split request. After it has processed
1846: the request it decrements the Irp count in the master Irp. If the
1847: count goes to zero then the master Irp is completed.
1848:
1849: Arguments:
1850:
1851: DeviceObject - Supplies the device object which represents the logical
1852: unit.
1853:
1854: Irp - Supplies the Irp which has completed.
1855:
1856: Context - Supplies a pointer to the SRB.
1857:
1858: Return Value:
1859:
1860: NT status
1861:
1862: --*/
1863:
1864: {
1865: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1866: PSCSI_REQUEST_BLOCK srb = Context;
1867: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1868: INTERLOCKED_RESULT irpCount;
1869: PIRP originalIrp = Irp->AssociatedIrp.MasterIrp;
1870: NTSTATUS status;
1871:
1872: //
1873: // Check SRB status for success of completing request.
1874: //
1875:
1876: if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
1877:
1878: DebugPrint((2,"ScsiTapeIoCompleteAssociated: IRP %lx, SRB %lx", Irp, srb));
1879:
1880: //
1881: // Release the queue if it is frozen.
1882: //
1883:
1884: if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
1885: ScsiClassReleaseQueue(DeviceObject);
1886: }
1887:
1888: ScsiClassInterpretSenseInfo(
1889: DeviceObject,
1890: srb,
1891: irpStack->MajorFunction,
1892: irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
1893: MAXIMUM_RETRIES - ((ULONG)irpStack->Parameters.Others.Argument4),
1894: &status);
1895:
1896: //
1897: // Return the highest error that occurs. This way warning take precedence
1898: // over success and errors take precedence over errors.
1899: //
1900:
1901: if ((ULONG) status > (ULONG) originalIrp->IoStatus.Status) {
1902:
1903: //
1904: // Ignore any requests which were flushed.
1905: //
1906:
1907: if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_REQUEST_FLUSHED) {
1908:
1909: originalIrp->IoStatus.Status = status;
1910:
1911: }
1912:
1913: }
1914:
1915:
1916: } // end if (SRB_STATUS(srb->SrbStatus) ...
1917:
1918: //
1919: // Return SRB to nonpaged pool.
1920: //
1921:
1922: if (srb->SrbFlags & SRB_FLAGS_ALLOCATED_FROM_ZONE) {
1923:
1924: ExInterlockedFreeToZone( deviceExtension->SrbZone,
1925: srb,
1926: deviceExtension->SrbZoneSpinLock);
1927:
1928: } else {
1929:
1930: ExFreePool(srb);
1931:
1932: }
1933:
1934: DebugPrint((2, "ScsiTapeIoCompleteAssociated: Partial xfer IRP %lx\n", Irp));
1935:
1936: //
1937: // Get next stack location. This original request is unused
1938: // except to keep track of the completing partial IRPs so the
1939: // stack location is valid.
1940: //
1941:
1942: irpStack = IoGetNextIrpStackLocation(originalIrp);
1943:
1944: //
1945: // Increment the status information with number of bytes transfered.
1946: //
1947:
1948: ExInterlockedAddUlong(&originalIrp->IoStatus.Information,
1949: Irp->IoStatus.Information,
1950: &deviceExtension->SplitRequestSpinLock );
1951:
1952: //
1953: //
1954: // If any of the asynchronous partial transfer IRPs fail with an error
1955: // with an error then the original IRP will return 0 bytes transfered.
1956: // This is an optimization for successful transfers.
1957: //
1958:
1959: if (NT_ERROR(originalIrp->IoStatus.Status)) {
1960:
1961: originalIrp->IoStatus.Information = 0;
1962:
1963: //
1964: // Set the hard error if necessary.
1965: //
1966:
1967: if (IoIsErrorUserInduced(originalIrp->IoStatus.Status)) {
1968:
1969: //
1970: // Store DeviceObject for filesystem.
1971: //
1972:
1973: IoSetHardErrorOrVerifyDevice(originalIrp, DeviceObject);
1974:
1975: }
1976:
1977: }
1978:
1979: //
1980: // Decrement and get the count of remaining IRPs.
1981: //
1982:
1983: irpCount = ExInterlockedDecrementLong(
1984: (PLONG)&irpStack->Parameters.Others.Argument1,
1985: &deviceExtension->SplitRequestSpinLock);
1986:
1987: DebugPrint((2, "ScsiTapeIoCompleteAssociated: Partial IRPs left %d\n",
1988: irpCount));
1989:
1990: if (irpCount == ResultZero) {
1991:
1992:
1993: #if DBG
1994: irpStack = IoGetCurrentIrpStackLocation(originalIrp);
1995:
1996: if (originalIrp->IoStatus.Information != irpStack->Parameters.Read.Length) {
1997: DebugPrint((1, "ScsiTapeIoCompleteAssociated: Short transfer. Request length: %lx, Return length: %lx, Status: %lx\n",
1998: irpStack->Parameters.Read.Length, originalIrp->IoStatus.Information, originalIrp->IoStatus.Status));
1999: }
2000: #endif
2001: //
2002: // All partial IRPs have completed.
2003: //
2004:
2005: DebugPrint((2,
2006: "ScsiTapeIoCompleteAssociated: All partial IRPs complete %lx\n",
2007: originalIrp));
2008:
2009: IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
2010: }
2011:
2012: //
2013: // Deallocate IRP and indicate the I/O system should not attempt any more
2014: // processing.
2015: //
2016:
2017: IoFreeIrp(Irp);
2018:
2019: return STATUS_MORE_PROCESSING_REQUIRED;
2020:
2021: } // end ScsiTapeIoCompleteAssociated()
2022:
2023:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.