Preempt reservation

A reservation can be preempted by issuing the appropriate IOCTL. The current reservation key is needed to successfully preempt the reservation. The current reservation key can be queried by issuing an IOCTL_STORAGE_PERSISTENT_RESERVE_IN IOCTL:
       PERSISTENT_RESERVE_COMMAND prcmd = { 0 };
        PPRI_RESERVATION_LIST prsl = NULL;
        ULONG AdditionalLength = 0;
        DWORD BytesReturned = 0;
        INT iStatus = 0, i, j;

        UCHAR  *bufDataRead = (UCHAR *) malloc(SENSE_BUFFER_SIZE * 2);

        ZeroMemory(bufDataRead, SENSE_BUFFER_SIZE * 2);

        prcmd.Size = sizeof(PERSISTENT_RESERVE_COMMAND);

        prcmd.PR_IN.ServiceAction    = RESERVATION_ACTION_READ_KEYS;
        prcmd.PR_IN.AllocationLength = sizeof(PRI_REGISTRATION_LIST);

        for (i = 0; i < 2; i++) {
                if (0 == i)
                        AdditionalLength = sizeof(PRI_RESERVATION_LIST);

                iStatus = DeviceIoControl(tape,
                                          IOCTL_STORAGE_PERSISTENT_RESERVE_IN,
                                          &prcmd,
                                          prcmd.Size,
                                          bufDataRead,
                                          AdditionalLength,
                                          &BytesReturned,
                                          NULL);

                if (0 == iStatus) {
                        free(bufDataRead);
                        return FALSE;
                }
                prsl = (PPRI_RESERVATION_LIST)bufDataRead;

                if (0 == i) {
                   AdditionalLength  = (ULONG)((prsl->AdditionalLength[0] & 0xff) << 12);
                   AdditionalLength |= (ULONG)((prsl->AdditionalLength[1] & 0xff) << 8);
                   AdditionalLength |= (ULONG)((prsl->AdditionalLength[2] & 0xff) << 4);
                   AdditionalLength |= (ULONG) (prsl->AdditionalLength[3] & 0xff);

                   AdditionalLength += sizeof(PRI_RESERVATION_LIST);

                   prcmd.PR_IN.AllocationLength = AdditionalLength;
                } else if (1 == i) {
                   for (j = 0; (j * sizeof(PRI_RESERVATION_DESCRIPTOR) 
                   + sizeof(PRI_RESERVATION_LIST))<= AdditionalLength; j++) {
                        printf("\nReservation 0x%08x%08x being examined at 
                        descriptor index %d.\n",
                       ((LARGE_INTEGER*)(prsl->Reservations[j].ReservationKey))
                        ->HighPart,
                       ((LARGE_INTEGER*)(prsl->Reservations[j].ReservationKey))
                        ->LowPart,
                           j);
                        }
                }
        }
When the reservation key is known, it can be preempted, meaning a new host can be the reservation holder, thus being able to interact with the target as needed.
 PRI_RESERVATION_DESCRIPTOR reservation = { 0 };
        PERSISTENT_RESERVE_COMMAND prcmd = { 0 };
        PRO_PARAMETER_LIST prolist = { 0 };
        DWORD BytesReturned = 0;
        INT iStatus = 0;

        UCHAR  bufDataRead[sizeof(PERSISTENT_RESERVE_COMMAND) 
        + sizeof(PRO_PARAMETER_LIST)] = { 0 };

        prcmd.Size = sizeof(PERSISTENT_RESERVE_COMMAND) + sizeof(PRO_PARAMETER_LIST);

        prcmd.PR_OUT.ParameterList[1] = 0x18;
        prcmd.PR_OUT.ServiceAction = 0x3;
        prcmd.PR_OUT.Type = 0x3;

        query_reserve(tape, &reservation);

        RtlCopyMemory(prolist.ReservationKey, reservation.ReservationKey, 8);
        RtlCopyMemory(prolist.ServiceActionReservationKey, 
        reservation.ReservationKey, 8);

        RtlCopyMemory(bufDataRead, &prcmd, sizeof(PERSISTENT_RESERVE_COMMAND));
        RtlCopyMemory(bufDataRead + sizeof(PERSISTENT_RESERVE_COMMAND), 
        &prolist, sizeof(PRO_PARAMETER_LIST));

        iStatus = DeviceIoControl(tape,
                                  IOCTL_STORAGE_PERSISTENT_RESERVE_OUT,
                                  bufDataRead,
                                  sizeof(bufDataRead),
                                  bufDataRead,
                                  sizeof(bufDataRead),
                                  &BytesReturned,
                                  NULL);

The query_reserve function can be implemented as explained earlier. Finally, if the reservation needs to be preempted on a different system than the original reservation holder, the OPEN_ALWAYS flag comes in handy. It allows the user to query the target's serial number, then queries the reservation key, and preempts the reservation.

Caution is advised when preempting reservations due to inherent risk of data loss if done incorrectly. Applications must make sure that they are clearing or preempting the appropriate reservation.