Annotation of ntddk/src/scsi/class/class.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.