|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1993 - Colorado Memory Systems, Inc.
4: All Rights Reserved
5:
6: Module Name:
7:
8: ioctl.c
9:
10: Abstract:
11:
12: Tape IOCTL support for NT Backup aplication.
13:
14: Revision History:
15:
16:
17:
18:
19: --*/
20:
21: //
22: // Includes
23: //
24:
25: #include <ntddk.h>
26: #include <ntddtape.h> // tape device driver I/O control codes
27: #include "common.h"
28: #include "q117.h"
29: #include "protos.h"
30: #include "cms.h"
31:
32:
33: NTSTATUS
34: q117IoCtlGetPosition (
35: IN PDEVICE_OBJECT DeviceObject,
36: IN PIRP Irp
37: )
38: /*++
39:
40: Routine Description:
41:
42:
43:
44: Arguments:
45:
46: DeviceObject
47:
48:
49: Return Value:
50:
51: NT Status
52:
53: --*/
54:
55: {
56: PQ117_CONTEXT context;
57: PTAPE_GET_POSITION currentPosition;
58: PLARGE_INTEGER offset;
59:
60: context = DeviceObject->DeviceExtension;
61: currentPosition = Irp->AssociatedIrp.SystemBuffer;
62:
63: Irp->IoStatus.Information = sizeof(TAPE_GET_POSITION);
64:
65: //
66: // signal no partition support
67: //
68: currentPosition->Partition = 0;
69:
70: //
71: // Fill in the CurrentOperation.Position based on the mode
72: //
73: offset = ¤tPosition->Offset;
74:
75: offset->HighPart = (LONG)0;
76:
77:
78: switch (context->CurrentOperation.Type) {
79:
80: case BackupInProgress:
81: offset->LowPart = context->CurrentOperation.BytesOnTape;
82: break;
83:
84: case RestoreInProgress:
85: offset->LowPart = context->CurrentOperation.BytesRead;
86: break;
87:
88: case NoOperation:
89: offset->LowPart = context->CurrentOperation.BytesRead;
90: break;
91:
92: }
93: offset->LowPart /= BLOCK_SIZE;
94:
95: CheckedDump(QIC117SHOWTD,("%d=GetPosition()",currentPosition->Offset.LowPart));
96:
97: return STATUS_SUCCESS;
98: }
99:
100: NTSTATUS
101: q117IoCtlGetMediaParameters (
102: IN PDEVICE_OBJECT DeviceObject,
103: IN PIRP Irp
104: )
105: /*++
106:
107: Routine Description:
108:
109:
110:
111: Arguments:
112:
113: DeviceObject
114:
115:
116: Return Value:
117:
118: NT Status
119:
120: --*/
121:
122: {
123: PQ117_CONTEXT context;
124: NTSTATUS ntStatus;
125:
126: context = DeviceObject->DeviceExtension;
127:
128: //
129: // Make sure there is a tape in the drive and that the tape information
130: // has been loaded
131: //
132: if (context->CurrentOperation.Type == NoOperation) {
133:
134: ntStatus = q117ConvertStatus(DeviceObject, q117CheckNewTape(context));
135:
136: } else {
137:
138: ntStatus = STATUS_SUCCESS;
139:
140: }
141:
142:
143: if ( NT_SUCCESS( ntStatus ) ) {
144: //
145: // Copy already formed (by q117CheckNewTape) information into callers buffer
146: //
147: Irp->IoStatus.Information = sizeof(TAPE_GET_MEDIA_PARAMETERS);
148:
149: *(PTAPE_GET_MEDIA_PARAMETERS)Irp->AssociatedIrp.SystemBuffer =
150: *context->CurrentTape.MediaInfo;
151:
152: }
153:
154: return ntStatus;
155: }
156:
157: NTSTATUS
158: q117IoCtlSetMediaParameters (
159: IN PDEVICE_OBJECT DeviceObject,
160: IN PIRP Irp
161: )
162: /*++
163:
164: Routine Description:
165:
166:
167:
168: Arguments:
169:
170: DeviceObject
171:
172:
173: Return Value:
174:
175: NT Status
176:
177: --*/
178:
179: {
180: PQ117_CONTEXT context;
181: PTAPE_SET_MEDIA_PARAMETERS setMedia;
182:
183: context = DeviceObject->DeviceExtension;
184:
185: setMedia = (PTAPE_SET_MEDIA_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
186:
187: CheckedDump((QIC117SHOWTD | QIC117WARN),("SetDriveParameters not implemented yet\n"));
188: CheckedDump(QIC117SHOWTD,("BlockSize: %x",setMedia->BlockSize));
189:
190: if (setMedia->BlockSize != BLOCK_SIZE)
191: return STATUS_INVALID_PARAMETER;
192: else
193: return STATUS_SUCCESS;
194: }
195:
196: NTSTATUS
197: q117IoCtlGetDriveParameters (
198: IN PDEVICE_OBJECT DeviceObject,
199: IN PIRP Irp
200: )
201: /*++
202:
203: Routine Description:
204:
205:
206:
207: Arguments:
208:
209: DeviceObject
210:
211:
212: Return Value:
213:
214: NT Status
215:
216: --*/
217:
218: {
219: PQ117_CONTEXT context;
220: PTAPE_GET_DRIVE_PARAMETERS driveInfo;
221:
222: context = DeviceObject->DeviceExtension;
223:
224: //
225: // Copy already formed (by q117CheckNewTape) information into callers buffer
226: //
227: //
228: driveInfo = (PTAPE_GET_DRIVE_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
229: Irp->IoStatus.Information = sizeof(TAPE_GET_DRIVE_PARAMETERS);
230:
231: driveInfo->ECC = TRUE;
232: driveInfo->Compression = FALSE;
233: driveInfo->DataPadding = FALSE;
234: driveInfo->ReportSetmarks = TRUE;
235: driveInfo->DefaultBlockSize = BLOCK_SIZE;
236: driveInfo->MaximumBlockSize = BLOCK_SIZE;
237: driveInfo->MinimumBlockSize = BLOCK_SIZE;
238: driveInfo->MaximumPartitionCount = 0;
239: driveInfo->FeaturesLow =
240: TAPE_DRIVE_ERASE_SHORT |
241: TAPE_DRIVE_ERASE_BOP_ONLY |
242: TAPE_DRIVE_TAPE_CAPACITY |
243: TAPE_DRIVE_TAPE_REMAINING |
244: TAPE_DRIVE_FIXED_BLOCK |
245: TAPE_DRIVE_WRITE_PROTECT |
246: TAPE_DRIVE_ECC |
247: TAPE_DRIVE_COMPRESSION |
248: TAPE_DRIVE_REPORT_SMKS |
249: TAPE_DRIVE_GET_ABSOLUTE_BLK |
250: TAPE_DRIVE_GET_LOGICAL_BLK;
251: driveInfo->FeaturesHigh =
252: TAPE_DRIVE_LOAD_UNLOAD |
253: TAPE_DRIVE_TENSION |
254: TAPE_DRIVE_LOCK_UNLOCK |
255: TAPE_DRIVE_ABSOLUTE_BLK |
256: TAPE_DRIVE_LOGICAL_BLK |
257: TAPE_DRIVE_END_OF_DATA |
258: TAPE_DRIVE_RELATIVE_BLKS |
259: TAPE_DRIVE_FILEMARKS |
260: TAPE_DRIVE_SEQUENTIAL_FMKS |
261: TAPE_DRIVE_SETMARKS |
262: TAPE_DRIVE_SEQUENTIAL_SMKS |
263: TAPE_DRIVE_REVERSE_POSITION |
264: TAPE_DRIVE_WRITE_SETMARKS |
265: TAPE_DRIVE_WRITE_FILEMARKS |
266: TAPE_DRIVE_FORMAT;
267:
268: driveInfo->FeaturesHigh &= ~TAPE_DRIVE_HIGH_FEATURES;
269:
270: return STATUS_SUCCESS;
271: }
272:
273: NTSTATUS
274: q117IoCtlSetDriveParameters (
275: IN PDEVICE_OBJECT DeviceObject,
276: IN PIRP Irp
277: )
278: /*++
279:
280: Routine Description:
281:
282:
283:
284: Arguments:
285:
286: DeviceObject
287:
288:
289: Return Value:
290:
291: NT Status
292:
293: --*/
294:
295: {
296: PQ117_CONTEXT context;
297: PTAPE_SET_DRIVE_PARAMETERS driveInfo;
298: NTSTATUS ntStatus;
299:
300: context = DeviceObject->DeviceExtension;
301:
302: //
303: // Copy already formed (by q117CheckNewTape) information into callers buffer
304: //
305: //
306: driveInfo = (PTAPE_SET_DRIVE_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
307:
308: CheckedDump((QIC117SHOWTD | QIC117WARN),("SetDriveParameters not implemented yet\n"));
309: CheckedDump(QIC117SHOWTD,("ECC: %x",driveInfo->ECC));
310: CheckedDump(QIC117SHOWTD,("Compression: %x",driveInfo->Compression));
311: CheckedDump(QIC117SHOWTD,("DataPadding: %x",driveInfo->DataPadding));
312: CheckedDump(QIC117SHOWTD,("ReportSetmarks: %x",driveInfo->ReportSetmarks));
313: ntStatus = STATUS_SUCCESS;
314: if (!driveInfo->ECC ||
315: driveInfo->Compression ||
316: driveInfo->DataPadding ||
317: !driveInfo->ReportSetmarks) {
318:
319: ntStatus = STATUS_INVALID_DEVICE_REQUEST;
320: }
321:
322: return ntStatus;
323: }
324:
325: NTSTATUS
326: q117IoCtlWriteMarks (
327: IN PDEVICE_OBJECT DeviceObject,
328: IN PIRP Irp
329: )
330: /*++
331:
332: Routine Description:
333:
334: Handle user request to write tape mark
335:
336: Arguments:
337:
338: DeviceObject
339:
340:
341: Return Value:
342:
343: NT Status
344:
345: --*/
346:
347: {
348: #ifndef NO_MARKS
349:
350: PQ117_CONTEXT context;
351: PTAPE_WRITE_MARKS tapeMarks = Irp->AssociatedIrp.SystemBuffer;
352: ULONG numMarks;
353: NTSTATUS ntStatus;
354: ULONG type;
355:
356: context = DeviceObject->DeviceExtension;
357:
358: //
359: // Make sure we are in write mode
360: //
361: ntStatus = q117ConvertStatus(DeviceObject, q117OpenForWrite(context));
362:
363: numMarks = tapeMarks->Count;
364: type = tapeMarks->Type;
365:
366: //
367: // Don't allow long/short filemarks
368: //
369: switch(type) {
370: case TAPE_LONG_FILEMARKS:
371: case TAPE_SHORT_FILEMARKS:
372: ntStatus = STATUS_INVALID_DEVICE_REQUEST;
373: }
374:
375: //
376: // Put as many marks as the user asked for, in the mark array
377: //
378: while (numMarks && NT_SUCCESS( ntStatus )) {
379:
380: context->MarkArray.MarkEntry[
381: context->MarkArray.TotalMarks].Type = tapeMarks->Type;
382:
383: context->MarkArray.MarkEntry[
384: context->MarkArray.TotalMarks].Offset =
385: context->CurrentOperation.BytesOnTape;
386:
387: --numMarks;
388:
389: ++context->MarkArray.TotalMarks;
390: ++context->CurrentMark;
391:
392: //
393: // Always make the (last mark) huge so we don't have to check
394: // for the end of the table in the rest of the code.
395: //
396: context->MarkArray.MarkEntry[
397: context->MarkArray.TotalMarks].Offset = 0xffffffff;
398:
399: //
400: // For each mark, write a "fake" block on the tape. This
401: // is due to the ntBackup program assuming that a filemark
402: // takes a block
403: //
404:
405: ntStatus = q117ConvertStatus(
406: DeviceObject,
407: q117WriteTape(NULL,BLOCK_SIZE,context)
408: );
409: }
410:
411: return ntStatus;
412:
413: #else
414:
415: return STATUS_INVALID_DEVICE_REQUEST;
416:
417: #endif
418: }
419:
420: NTSTATUS
421: q117IoCtlSetPosition (
422: IN PDEVICE_OBJECT DeviceObject,
423: IN PIRP Irp
424: )
425: /*++
426:
427: Routine Description:
428:
429:
430:
431: Arguments:
432:
433: DeviceObject
434:
435:
436: Return Value:
437:
438: NT Status
439:
440: --*/
441:
442: {
443: PQ117_CONTEXT context;
444: PTAPE_SET_POSITION tapePosition = Irp->AssociatedIrp.SystemBuffer;
445: STATUS status;
446: NTSTATUS ntStatus;
447: IO_REQUEST ioreq;
448: ULONG offset;
449: #ifndef NO_MARKS
450: int x = 0;
451: #endif
452:
453: context = DeviceObject->DeviceExtension;
454:
455: status = NoErr;
456: ntStatus = STATUS_SUCCESS;
457:
458: if (context->CurrentOperation.Type != NoOperation) {
459: switch(context->CurrentOperation.Type) {
460:
461: case BackupInProgress:
462: status = q117EndWriteOperation(context);
463: break;
464:
465: case RestoreInProgress:
466: if (
467: tapePosition->Method == TAPE_REWIND
468: ) {
469: status = q117EndReadOperation(context);
470: }
471:
472: break;
473: }
474: }
475:
476: context->CurrentOperation.Position = tapePosition->Method;
477: switch(tapePosition->Method) {
478:
479: case TAPE_REWIND:
480:
481: CheckedDump(QIC117INFO,("Rewind()\n"));
482: status = q117DoCmd(&ioreq, DEject, NULL, context);
483:
484: // context->TapeStatus.Status |= TAPE_STATUS_BEGINNING_OF_MEDIA;
485: // context->TapeStatus.Status &= ~TAPE_STATUS_END_OF_MEDIA;
486:
487: context->CurrentOperation.BytesRead = 0;
488:
489: #ifndef NO_MARKS
490: context->CurrentMark = 0;
491: #endif
492: break;
493:
494: case TAPE_LOGICAL_BLOCK:
495: case TAPE_ABSOLUTE_BLOCK:
496:
497: CheckedDump(QIC117SHOWTD,(
498: "%s SeekBlock(%d)\n",
499: tapePosition->Method==TAPE_LOGICAL_BLOCK?"Logical":"Absolute",
500: tapePosition->Offset.LowPart
501: ));
502:
503: offset = (tapePosition->Offset.LowPart)*BLOCK_SIZE;
504:
505: ntStatus = q117SeekToOffset(offset, context, DeviceObject);
506:
507: break;
508:
509: case TAPE_SPACE_END_OF_DATA:
510: //
511: // This will be taken care of when backup starts
512: // by using the context->CurrentOperation.Position
513: //
514: // It is assumed that this function will only be called prior
515: // to a backup operation only.
516:
517: CheckedDump(QIC117SHOWTD,("SeekEOD()\n"));
518: context->CurrentOperation.BytesRead =
519: context->ActiveVolume.DataSize;
520:
521: #ifndef NO_MARKS
522: context->CurrentMark = context->MarkArray.TotalMarks;
523: #endif
524:
525: // context->TapeStatus.Status |= TAPE_STATUS_END_OF_MEDIA;
526: // context->TapeStatus.Status &= ~TAPE_STATUS_BEGINNING_OF_MEDIA;
527: break;
528:
529:
530: case TAPE_SPACE_RELATIVE_BLOCKS:
531:
532:
533: CheckedDump(QIC117SHOWTD,("SeekRelBlock(%d)\n",tapePosition->Offset.LowPart));
534: //
535: // Convert relative offset into absolute
536: //
537: offset = (LONG)context->CurrentOperation.BytesRead +
538: ((LONG)tapePosition->Offset.LowPart*BLOCK_SIZE);
539:
540: //
541: // Perform absolute seek.
542: //
543: ntStatus = q117SeekToOffset(offset,context, DeviceObject);
544:
545: break;
546:
547: #ifndef NO_MARKS
548: case TAPE_SPACE_SETMARKS:
549: ++x;
550: case TAPE_SPACE_FILEMARKS:
551: ++x;
552: case TAPE_SPACE_SEQUENTIAL_FMKS:
553: ++x;
554: case TAPE_SPACE_SEQUENTIAL_SMKS:
555: if (1) {
556: static char *type[4] = {"SequentialSet","SequentialFile","File","Set"};
557:
558: CheckedDump(QIC117SHOWTD,("Seek%sMark(%d)\n",type[x],tapePosition->Offset.LowPart));
559: }
560: ntStatus = q117FindMark(tapePosition->Method,
561: tapePosition->Offset.LowPart, context, DeviceObject);
562: break;
563: #else
564: case TAPE_SPACE_SETMARKS:
565: case TAPE_SPACE_FILEMARKS:
566: case TAPE_SPACE_SEQUENTIAL_FMKS:
567: case TAPE_SPACE_SEQUENTIAL_SMKS:
568: #endif
569: default:
570: CheckedDump(QIC117DBGP,("TAPE: Position: Invalid Position Code (%x)\n",
571: tapePosition->Method));
572:
573: ntStatus = STATUS_INVALID_DEVICE_REQUEST;
574: break;
575:
576: } // end switch(tapePosition->Method)
577:
578: if (status)
579: ntStatus = q117ConvertStatus(DeviceObject, status);
580:
581: return ntStatus;
582:
583: }
584:
585: #ifndef NO_MARKS
586: NTSTATUS
587: q117FindMark(
588: ULONG Type,
589: LONG Number,
590: PQ117_CONTEXT Context,
591: IN PDEVICE_OBJECT DeviceObject
592: )
593:
594: /*++
595:
596: Routine Description:
597:
598:
599:
600: Arguments:
601:
602:
603: Return Value:
604:
605: NT Status
606:
607: --*/
608:
609: {
610: NTSTATUS ntStatus;
611: BOOLEAN forwardSeek;
612:
613: ntStatus = STATUS_SUCCESS;
614:
615: //
616: // Convert the SetPosition commands into WriteMark types
617: //
618: switch(Type) {
619:
620: case TAPE_SPACE_SEQUENTIAL_FMKS:
621:
622: //
623: // If sequential mark, then always start from the first mark.
624: //
625: Context->CurrentMark = 0;
626:
627: case TAPE_SPACE_FILEMARKS:
628:
629: Type = TAPE_FILEMARKS;
630: break;
631:
632: case TAPE_SPACE_SEQUENTIAL_SMKS:
633:
634: //
635: // If sequential mark, then always start from the first mark.
636: //
637: Context->CurrentMark = 0;
638:
639: case TAPE_SPACE_SETMARKS:
640:
641: Type = TAPE_SETMARKS;
642: break;
643:
644: }
645:
646: if (Number > 0) {
647: forwardSeek = TRUE;
648: } else {
649: forwardSeek = FALSE;
650: }
651:
652:
653: //
654: // Now seek the appropriate amount
655: //
656: while (NT_SUCCESS( ntStatus ) && Number != 0) {
657:
658: if (forwardSeek) {
659:
660: if (Context->CurrentMark >= Context->MarkArray.TotalMarks) {
661:
662: ntStatus = STATUS_END_OF_MEDIA;
663:
664: } else {
665:
666: if (Context->MarkArray.MarkEntry[Context->CurrentMark].Type ==
667: Type) {
668:
669: //
670: // If we found one, decrement the count
671: //
672:
673: --Number;
674:
675:
676: //
677: // Don't increment the current mark on the last one we
678: // find. This is because current mark points to
679: // the mark we are going to hit next.
680: //
681:
682: if (Number) {
683:
684: ++Context->CurrentMark;
685: }
686:
687: } else {
688:
689: ++Context->CurrentMark;
690:
691: }
692: }
693:
694: } else {
695:
696: if (Context->CurrentMark == 0) {
697:
698: ntStatus = STATUS_END_OF_MEDIA;
699:
700: } else {
701:
702: --Context->CurrentMark;
703:
704: if (Context->MarkArray.MarkEntry[Context->CurrentMark].Type ==
705: Type) {
706:
707: ++Number;
708:
709: }
710:
711: }
712:
713: }
714:
715: }
716:
717: if (NT_SUCCESS( ntStatus )) {
718:
719: if (Context->CurrentMark >= Context->MarkArray.TotalMarks) {
720:
721: ntStatus = STATUS_END_OF_MEDIA;
722:
723: } else {
724:
725: //
726: // Seek to proper location. Note: forward seek
727: // seeks to block after file mark (successive read will return
728: // block after filemark.
729: // A backward seek will position at the filemark. The next read
730: // will return filemark found, and successive reads will read
731: // data after the mark)
732: //
733: ntStatus = q117SeekToOffset(
734: Context->MarkArray.MarkEntry[Context->CurrentMark].Offset+
735: (forwardSeek?BLOCK_SIZE:0),
736: Context,
737: DeviceObject
738: );
739:
740: }
741:
742: }
743:
744: return ntStatus;
745: }
746: #endif
747:
748: NTSTATUS
749: q117SeekToOffset(
750: ULONG Offset,
751: PQ117_CONTEXT Context,
752: IN PDEVICE_OBJECT DeviceObject
753: )
754:
755: /*++
756:
757: Routine Description:
758:
759: Seek to specified offset on the tape (absolute offset from 0) in bytes
760:
761: Arguments:
762:
763: Offset - Bytes from begining of the volume to seek.
764:
765: Return Value:
766:
767: NT Status
768:
769: --*/
770:
771: {
772: NTSTATUS ntStatus;
773:
774:
775: CheckedDump(QIC117SHOWTD,("Absolute seek: %x\n",Offset));
776:
777: ntStatus = STATUS_SUCCESS;
778:
779: //
780: // If not in read mode, switch into read mode
781: //
782: if (Context->CurrentOperation.Type == NoOperation) {
783:
784: ntStatus = q117OpenForRead(0, Context, DeviceObject);
785:
786: //
787: // if there is no data on the tape
788: //
789: if (ntStatus == STATUS_NO_DATA_DETECTED) {
790: return ntStatus;
791: }
792:
793: Context->CurrentOperation.Type = RestoreInProgress;
794: }
795:
796:
797: if (Offset < Context->CurrentOperation.BytesRead) {
798:
799: //
800: // Backward seek, so stop current operation,
801: // rewind to begining of volume, and drop
802: // through to a forward seek.
803: //
804:
805: ntStatus = q117ConvertStatus(
806: DeviceObject,
807: q117EndReadOperation(Context)
808: );
809:
810: if (NT_SUCCESS(ntStatus)) {
811:
812: ntStatus = q117OpenForRead(0, Context, DeviceObject);
813:
814: //
815: // if there is no data on the tape
816: //
817: if (ntStatus == STATUS_NO_DATA_DETECTED) {
818: return ntStatus;
819: }
820:
821: Context->CurrentOperation.Type = RestoreInProgress;
822: }
823: }
824:
825:
826: if (NT_SUCCESS(ntStatus)) {
827: //
828: // Forward seek only (if we were doing a backward seek, the operation
829: // has been re-started this point and BytesRead == 0)
830: //
831: Offset -= Context->CurrentOperation.BytesRead;
832:
833: //
834: // Skip to the appropriate place
835: //
836: ntStatus = q117ConvertStatus(
837: DeviceObject,
838: q117SkipBlock(&Offset, Context)
839: );
840:
841: }
842:
843: return ntStatus;
844: }
845:
846: NTSTATUS
847: q117IoCtlErase (
848: IN PDEVICE_OBJECT DeviceObject,
849: IN PIRP Irp
850: )
851: /*++
852:
853: Routine Description:
854:
855:
856:
857: Arguments:
858:
859: DeviceObject
860:
861:
862: Return Value:
863:
864: NT Status
865:
866: --*/
867:
868: {
869: PQ117_CONTEXT context;
870: NTSTATUS ntStatus;
871: STATUS status;
872:
873: context = DeviceObject->DeviceExtension;
874:
875: //
876: // Complete any operation in progress
877: //
878: switch(context->CurrentOperation.Type) {
879:
880: case BackupInProgress:
881: status = q117EndWriteOperation(context);
882: break;
883:
884: case RestoreInProgress:
885: status = q117EndReadOperation(context);
886: break;
887: }
888:
889: //
890: // Make sure there is a tape in the drive and that the tape information
891: // has been loaded
892: //
893: ntStatus = q117ConvertStatus(
894: DeviceObject,
895: q117CheckNewTape(context));
896:
897: if ( NT_SUCCESS( ntStatus ) ) {
898: //
899: // Don't allow an erase if write protected
900: //
901: if (context->CurrentTape.MediaInfo->WriteProtected) {
902: return STATUS_MEDIA_WRITE_PROTECTED;
903: }
904:
905: //
906: // Erase the tape
907: //
908: status = q117EraseQ(context);
909:
910: ntStatus = q117ConvertStatus(DeviceObject, status);
911: }
912:
913: return ntStatus;
914: }
915:
916: NTSTATUS
917: q117IoCtlPrepare (
918: IN PDEVICE_OBJECT DeviceObject,
919: IN PIRP Irp
920: )
921: /*++
922:
923: Routine Description:
924:
925:
926:
927: Arguments:
928:
929: DeviceObject
930:
931:
932: Return Value:
933:
934: NT Status
935:
936: --*/
937:
938: {
939: PQ117_CONTEXT context;
940: NTSTATUS ntStatus;
941: STATUS status;
942: PTAPE_PREPARE tapePrepare;
943: IO_REQUEST ioreq;
944: QIC40_VENDOR_UNIQUE vendorUnique;
945: LONG numberBad;
946:
947: context = DeviceObject->DeviceExtension;
948:
949: status = NoErr;
950:
951: //
952: // Complete any operation in progress
953: //
954: switch(context->CurrentOperation.Type) {
955:
956: case BackupInProgress:
957: status = q117EndWriteOperation(context);
958: break;
959:
960: case RestoreInProgress:
961: status = q117EndReadOperation(context);
962: break;
963: }
964:
965: //
966: // All prepare except LOCK and UNLOCK operations rewind the media.
967: //
968: tapePrepare = Irp->AssociatedIrp.SystemBuffer;
969:
970: if ((tapePrepare->Operation != TAPE_LOCK) &&
971: (tapePrepare->Operation != TAPE_UNLOCK)) {
972: context->CurrentOperation.BytesRead = 0;
973: context->CurrentOperation.Position = 0;
974: #ifndef NO_MARKS
975: context->CurrentMark = 0;
976: #endif
977: }
978:
979:
980: if (status) {
981: return q117ConvertStatus(DeviceObject, status);
982: }
983:
984: ntStatus = STATUS_SUCCESS;
985:
986: switch (tapePrepare->Operation) {
987:
988: case TAPE_LOAD:
989: CheckedDump(QIC117SHOWTD,("TAPE_LOAD ... "));
990: ntStatus = q117ConvertStatus(DeviceObject, q117CheckNewTape(context));
991: break;
992:
993: case TAPE_UNLOAD:
994:
995: //
996: // Just rewind the tape
997: //
998: CheckedDump(QIC117SHOWTD,("TAPE_UNLOAD ... "));
999: ntStatus = q117ConvertStatus (
1000: DeviceObject,
1001: q117DoCmd(&ioreq, DEject, NULL, context) );
1002:
1003: break;
1004:
1005: case TAPE_TENSION:
1006:
1007: CheckedDump(QIC117SHOWTD,("TAPE_TENSION ... "));
1008: ntStatus = q117ConvertStatus (
1009: DeviceObject,
1010: q117DoCmd(&ioreq, DReten, NULL, context) );
1011:
1012: break;
1013:
1014: case TAPE_UNLOCK:
1015: CheckedDump(QIC117SHOWTD,("UN"));
1016: case TAPE_LOCK:
1017: CheckedDump(QIC117SHOWTD,("LOCK TAPE ..."));
1018:
1019: //
1020: // These commands mean nothing for a QIC-40 drive. However, the current
1021: // operation will be flushed allowing user to remove cartridge.
1022: //
1023: break;
1024:
1025: case TAPE_FORMAT:
1026: CheckedDump(QIC117SHOWTD,("TAPE_FORMAT ... "));
1027:
1028: ntStatus = q117ConvertStatus (
1029: DeviceObject,
1030: q117Format(
1031: &numberBad,
1032: TRUE,
1033: &vendorUnique,
1034: context ) );
1035: break;
1036:
1037: default:
1038: CheckedDump(QIC117SHOWTD,("INVALID ... "));
1039:
1040: ntStatus = STATUS_INVALID_DEVICE_REQUEST;
1041:
1042: } // end switch (tapePrepare->Operation)
1043:
1044: return ntStatus;
1045: }
1046:
1047: NTSTATUS
1048: q117IoCtlGetStatus (
1049: IN PDEVICE_OBJECT DeviceObject,
1050: IN PIRP Irp
1051: )
1052: /*++
1053:
1054: Routine Description:
1055:
1056:
1057:
1058: Arguments:
1059:
1060: DeviceObject
1061:
1062:
1063: Return Value:
1064:
1065: NT Status
1066:
1067: --*/
1068:
1069: {
1070: PQ117_CONTEXT context;
1071: // PTAPE_STATUS tapeStatus;
1072: STATUS status;
1073:
1074: context = DeviceObject->DeviceExtension;
1075:
1076:
1077: //
1078: // Complete any operation in progress
1079: //
1080: switch(context->CurrentOperation.Type) {
1081:
1082: case BackupInProgress:
1083: status = NoErr;
1084: break;
1085:
1086: case RestoreInProgress:
1087: status = NoErr;
1088: break;
1089:
1090: case NoOperation:
1091: status = q117CheckNewTape(context);
1092: break;
1093:
1094: default:
1095: status = FCodeErr;
1096:
1097: }
1098:
1099: //tapeStatus = Irp->UserBuffer;
1100:
1101: //
1102: // Is this supported in the tape API ?????
1103: //
1104: // *tapeStatus = context->TapeStatus;
1105:
1106: //
1107: // Reset media changed flag.
1108: //
1109: // context->TapeStatus.Status &= ~TAPE_STATUS_MEDIA_CHANGED;
1110:
1111: return q117ConvertStatus(DeviceObject, status);
1112: }
1113:
1114: NTSTATUS
1115: q117IoCtlReadAbs (
1116: IN PDEVICE_OBJECT DeviceObject,
1117: IN PIRP Irp
1118: )
1119: /*++
1120:
1121: Routine Description:
1122:
1123:
1124:
1125: Arguments:
1126:
1127: DeviceObject
1128:
1129:
1130: Return Value:
1131:
1132: NT Status
1133:
1134: --*/
1135:
1136: {
1137: PQ117_CONTEXT context;
1138: PSEGMENT_BUFFER bufferInfo;
1139: PVOID scrbuf;
1140: PIO_REQUEST ioreq;
1141: PCMS_RW_ABS readWrite;
1142: STATUS status;
1143: ULONG len;
1144: PIO_STACK_LOCATION irpStack;
1145:
1146: context = DeviceObject->DeviceExtension;
1147: readWrite = Irp->AssociatedIrp.SystemBuffer;
1148: irpStack = IoGetCurrentIrpStackLocation(Irp);
1149:
1150: scrbuf = q117GetFreeBuffer(&bufferInfo,context);
1151:
1152: status=q117IssIOReq(
1153: scrbuf,
1154: DRead,
1155: readWrite->Block,
1156: bufferInfo,
1157: context
1158: );
1159:
1160: if (!status) {
1161:
1162: //
1163: // Wait for data to be written
1164: //
1165: ioreq=q117Dequeue(WaitForItem,context);
1166:
1167: status = ioreq->Status;
1168:
1169: }
1170:
1171: readWrite->Status = status;
1172:
1173: len = BYTES_PER_SECTOR*readWrite->Count;
1174:
1175: if (len > irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
1176:
1177: len = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
1178:
1179: }
1180:
1181: RtlMoveMemory(
1182: readWrite+1,
1183: scrbuf,
1184: len
1185: );
1186:
1187: Irp->IoStatus.Information = sizeof(CMS_RW_ABS)+len;
1188:
1189: return q117ConvertStatus(DeviceObject, status);
1190:
1191:
1192: }
1193:
1194: NTSTATUS
1195: q117IoCtlWriteAbs (
1196: IN PDEVICE_OBJECT DeviceObject,
1197: IN PIRP Irp
1198: )
1199: /*++
1200:
1201: Routine Description:
1202:
1203:
1204:
1205: Arguments:
1206:
1207: DeviceObject
1208:
1209:
1210: Return Value:
1211:
1212: NT Status
1213:
1214: --*/
1215:
1216: {
1217: PQ117_CONTEXT context;
1218: PSEGMENT_BUFFER bufferInfo;
1219: PVOID scrbuf;
1220: PIO_REQUEST ioreq;
1221: PCMS_RW_ABS readWrite;
1222: STATUS status;
1223:
1224: context = DeviceObject->DeviceExtension;
1225: readWrite = Irp->AssociatedIrp.SystemBuffer;
1226:
1227: scrbuf = q117GetFreeBuffer(&bufferInfo,context);
1228:
1229: RtlMoveMemory(
1230: scrbuf,
1231: readWrite+1,
1232: BYTES_PER_SECTOR*readWrite->Count
1233: );
1234:
1235: status = q117IssIOReq(
1236: scrbuf,
1237: DWrite,
1238: readWrite->Block,
1239: bufferInfo,
1240: context);
1241:
1242: if (!status) {
1243:
1244: //
1245: // Wait for data to be written
1246: //
1247: ioreq=q117Dequeue(WaitForItem,context);
1248:
1249: status = ioreq->Status;
1250:
1251: }
1252:
1253: readWrite->Status = status;
1254:
1255: return q117ConvertStatus(DeviceObject, status);
1256:
1257: }
1258:
1259: STATUS
1260: q117CheckNewTape (
1261: PQ117_CONTEXT Context
1262: )
1263: /*++
1264:
1265: Routine Description:
1266:
1267: This routine checks for new tape and reads header if necessary
1268:
1269: Arguments:
1270:
1271: Context - Current context information
1272:
1273: Return Value:
1274:
1275: NT Status
1276:
1277: --*/
1278:
1279: {
1280: STATUS stat;
1281: IO_REQUEST ioreq;
1282: PTAPE_HEADER header;
1283: VOLUME_TABLE_ENTRY tempVolume;
1284: UCHAR tapeType;
1285: BOOLEAN found;
1286: BOOLEAN notNt;
1287: USHORT volumesRead;
1288: DRIVE_CAPACITY driveCapacity;
1289: SEGMENT curseg;
1290:
1291:
1292: //
1293: // Check to see if there is a tape in the drive
1294: //
1295: stat = q117DoCmd(&ioreq, DGetCart, &tapeType, Context);
1296:
1297: //
1298: // If we found a tape and need to read the header and volume tables,
1299: // do it now.
1300: //
1301: if (stat == NewCart) {
1302: // Context->TapeStatus.Status |= TAPE_STATUS_MEDIA_CHANGED;
1303: }
1304:
1305: if (stat == NewCart ||
1306: (stat == NoErr && Context->CurrentTape.State == NeedInfoLoaded) ) {
1307:
1308: CheckedDump(QIC117SHOWTD,("New Cart Detected\n"));
1309:
1310: //
1311: // Check to see if there is a tape in the drive
1312: //
1313:
1314: stat = q117DoCmd(&ioreq, DClearNewCart, NULL, Context);
1315:
1316: if (stat) {
1317: return stat;
1318: }
1319:
1320: //
1321: // Saw new cart, so set need loaded flag
1322: //
1323: Context->CurrentTape.State = NeedInfoLoaded;
1324:
1325: // clear no media flag and end of media flag
1326: // Context->TapeStatus.Status &=
1327: // ~(TAPE_STATUS_NO_MEDIA|TAPE_STATUS_END_OF_MEDIA);
1328:
1329: // Set bom and device ready.
1330: // Context->TapeStatus.Status |=
1331: // TAPE_STATUS_DEVICE_READY|TAPE_STATUS_BEGINNING_OF_MEDIA;
1332:
1333: //
1334: // Check to see if tape is write protected
1335: //
1336: if (stat = q117DoCmd(&ioreq, DSndWPro, NULL, Context)) {
1337:
1338: if (stat != WProt) {
1339: return stat;
1340: }
1341:
1342: }
1343:
1344: Context->CurrentTape.MediaInfo->WriteProtected = (stat == WProt);
1345: if (stat == WProt) {
1346: // Context->TapeStatus.Status |= TAPE_STATUS_WRITE_PROTECTED;
1347: }
1348:
1349: //
1350: // Check to see if drive is formatted
1351: //
1352: stat = q117DoCmd(&ioreq, DGetCap, &driveCapacity, Context);
1353:
1354: if (stat) {
1355: return stat;
1356: }
1357:
1358: //
1359: // If tape not referenced.
1360: //
1361: if (driveCapacity.referenced == FALSE) {
1362: return BadFmt;
1363: }
1364:
1365: //
1366: // Check to see if tape is correct format
1367: //
1368: stat = q117DoCmd(&ioreq, DChkFmt, NULL, Context);
1369:
1370: if (stat) {
1371: if (stat == WrongFmt) {
1372: Context->CurrentTape.MediaInfo->WriteProtected =
1373: TRUE;
1374: stat = NoErr;
1375: } else {
1376: return stat;
1377: }
1378: }
1379:
1380: //
1381: // Now read the tape header (and bad sector map)
1382: //
1383: if (stat = q117LoadTape(&header,Context)) {
1384: return stat;
1385: }
1386: CheckedDump(QIC117SHOWTD,("LoadTape successful\n"));
1387:
1388: //
1389: // If this capacity not supported by this drive,
1390: // (i.e.. Pegasus cart in a QIC-40 drive)
1391: // return invalid format
1392: //
1393: if (header->FormatCode != driveCapacity.TapeFormatCode) {
1394: return BadFmt;
1395: }
1396:
1397: //
1398: // Copy over bad sector map, etc.
1399: //
1400: RtlMoveMemory(
1401: Context->CurrentTape.TapeHeader,
1402: header,
1403: sizeof(*Context->CurrentTape.TapeHeader) );
1404:
1405: //
1406: // Now scan volume list and get last volume on tape as well as the
1407: // NT volume (if one exists
1408: //
1409:
1410: if (stat = q117SelectTD(Context))
1411: return stat;
1412:
1413: volumesRead = 0;
1414:
1415: found = FALSE;
1416:
1417: do {
1418: /* get a volume directory from the tape (if error then)*/
1419: stat = q117ReadVolumeEntry(&tempVolume,Context);
1420:
1421: if (stat && (stat != EndOfVol))
1422: return stat;
1423:
1424: if (!stat) {
1425: volumesRead++;
1426:
1427: //
1428: // For now, let the system find ANY volume type and select
1429: // it. This will allow NT Backup software to read the
1430: // volume and detect that it is a non-nt format.
1431: // To do this, the if statement is removed, allowing
1432: // the first volume found, be the one that we select.
1433: //
1434: if (!(tempVolume.VendorSpecific &&
1435: tempVolume.Vendor.cms_QIC40.OpSysType == OP_WINDOWS_NT)) {
1436:
1437: Context->CurrentOperation.BytesOnTape =
1438: Context->CurrentOperation.BytesRead = 0;
1439:
1440: notNt = TRUE;
1441:
1442: #ifndef NO_MARKS
1443: Context->MarkArray.TotalMarks = 0;
1444: Context->CurrentMark = Context->MarkArray.TotalMarks;
1445: Context->MarkArray.MarkEntry[Context->CurrentMark].Offset =
1446: 0xffffffff;
1447: #endif
1448:
1449: /* force the data size to be the entire backup */
1450: tempVolume.DataSize = 0;
1451: curseg = tempVolume.StartSegment;
1452: while (curseg <= tempVolume.EndingSegment) {
1453:
1454: tempVolume.DataSize +=
1455: q117GoodDataBytes(
1456: curseg,
1457: Context);
1458: ++curseg;
1459:
1460:
1461: }
1462:
1463: } else {
1464:
1465: notNt = FALSE;
1466:
1467: }
1468: found = TRUE;
1469: Context->ActiveVolume = tempVolume;
1470: }
1471:
1472: } while (!stat && volumesRead < Context->CurrentTape.MaximumVolumes);
1473:
1474: if (stat = q117EndRest(Context))
1475: return(stat);
1476:
1477: //
1478: // If we did not find a volume, then signal others that
1479: // the ActiveVolume information is invalid.
1480: //
1481: if (!found)
1482: Context->ActiveVolumeNumber = 0;
1483:
1484: //
1485: // Zero out bytes saved (incase user trys to read)
1486: // Also set CurrentOperation.BytesRead to zero (start of tape)
1487: //
1488: Context->CurrentOperation.BytesOnTape =
1489: Context->CurrentOperation.BytesRead = 0;
1490:
1491: //
1492: // Flag that we have done everything
1493: //
1494: Context->CurrentTape.State = TapeInfoLoaded;
1495:
1496: #ifndef NO_MARKS
1497:
1498: //
1499: // Read the mark list from the active volume
1500: //
1501: if (found && !notNt) {
1502:
1503: stat = q117GetMarks(Context);
1504:
1505: }
1506:
1507: #endif
1508:
1509: //
1510: // If no more pressing error, return NewCart
1511: // so application can be aware of the new insertion.
1512: //
1513: if (stat == NoErr) {
1514: stat = NewCart;
1515: }
1516:
1517: } else {
1518:
1519: if (stat == NoTape) {
1520: // Context->TapeStatus.Status |= TAPE_STATUS_NO_MEDIA;
1521: Context->ActiveVolumeNumber = 0;
1522: Context->CurrentOperation.BytesOnTape =
1523: Context->CurrentOperation.BytesRead = 0;
1524:
1525: #ifndef NO_MARKS
1526: Context->MarkArray.TotalMarks = 0;
1527: Context->CurrentMark = Context->MarkArray.TotalMarks;
1528: Context->MarkArray.MarkEntry[Context->CurrentMark].Offset =
1529: 0xffffffff;
1530: #endif
1531:
1532: }
1533:
1534: }
1535:
1536: return stat;
1537: }
1538:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.