t10_spc_pr.c revision aedf2b3bb56b025fcaf87b49ec6c8aeea07f16d7
* | Implementation of SPC-3 Persistent Reserve emulation | * []------------------------------------------------------------------[] * | spc_pgr_is_conflicting * | PGR reservation conflict checking. * | SPC-3, Revision 23, Table 31 case SCMD_GDIAG:
/* SCMD_RECEIVE_DIAGNOSTIC_RESULTS */ case SCMD_SDIAG:
/* SCMD_SEND_DIAGNOSTIC_RESULTS */ * As per SPC-3, Revision 23, Table 31 * As per SPC-3, Revision 23, Section 6.23 switch ((
cdb[
1] &
0x1f)) {
* SPC-3, Revision 23, Section 6.29 switch ((
cdb[
1] &
0x1F)) {
* Exclusive Access, and EA Registrants Only * | spc_npr_check -- NON-PERSISTENT RESERVE check of I_T_L * | Refer to SPC-2, Section 5.5.1, Tables 10 * If a logical unit has been reserved by any RESERVE command and * is still reserved by any initiator, all PERSISTENT RESERVE IN * and all PRESISTENT RESERVE OUT commands shall conflict regardless * of initiator or service action and shall terminate with a * RESERVATION CONLICT status. SPC-2 section 5.5.1. "NPR%x LUN%d CDB:%s - spc_npr_check(Reservation:%s)\n",
* | spc_pgr_check -- PERSISTENT_RESERVE {IN|OUT} check of I_T_L * | Refer to SPC-3, Section 5.6.1, Tables 31 * If no reservations exist, allow all remaining command types. * If a logical unit has executed a PERSISTENT RESERVE OUT command * with the REGISTER or REGISTER AND IGNORE EXISTING KEY service * action and is still registered by any initiator, all RESERVE * commands and all RELEASE commands regardless of initiator shall * conflict and shall terminate with a RESERVATION CONFLICT status. * CRH bit 0, no support for exception defined in * At this point we know there is at least one reservation. * If there is no reservation set on this service delivery * port then conflict all remaining command types. * Check the command against the reservation type for this port. ?
"Write Exclusive, Registrants Only" ?
"Exclusive Access, Registrants Only" ?
"Write Exclusive, All Registrants" ?
"Exclusive Access, All Registrants" :
"Uknown reservation type",
* | spc_cmd_reserve6 -- RESERVE(6) command * The ways to get in here are, * 1) to be the owner of the reservation (SPC-2 section 7.21.2) * 2) reservation not applied, nobody is the owner. * | spc_cmd_release6 -- RELEASE(6) command * The ways to get in here are, * 1) to be the owner of the reservation * 2) reservation not applied, nobody is the owner. * | spc_cmd_pr_in -- PERSISTENT_RESERVE IN * | Refer to SPC-3, Section 6.1, Tables ?? and ?? * Information obtained from: * Section 6.11 PERSISTENCE RESERVE IN * Need to generate a CHECK CONDITION with ILLEGAL REQUEST * and INVALID FIELD IN CDB (0x24/0x00) if any of the following is * (1) The SERVICE ACTION field is 004h - 01fh, * (2) The reserved area in byte 1 is set, * (3) The reserved area in bytes 2 thru 6 are set, * (4) If any of the reserved bits in the CONTROL byte are set. * Information obtained from: * Section 6.11 PERSISTENCE RESERVE IN * Acquire ALLOCATION LENGTH from bytes 7, 8 * A zero(0) length allocation is not an error and we should just * acknowledge the operation. "PGR%x LUN%d CDB:%s - spc_cmd_pr_in, len = 0\n",
* Allocate space with an alignment that will work for any casting. * Lack of memory is not fatal, just too busy * Start processing, lock reservation * Per SPC-3, Revision 23, Table 102, validate ranget of service actions * Complete processing, unlock reservation * Now send the selected Persistent Reservation response back * | Refer to SPC-3, Section 6.1, Tables ?? and ?? "PGRIN readkeys - key:%016lx, i_name:%s\n",
break;
/* No room left, leave now */ * | Refer to SPC-3, Section 6.1, Tables ?? and ?? "key:%016lx i_name:%s scope:%d type:%d \n",
break;
/* No room left, leave now */ * | Refer to SPC-3, Section 6.1, Tables ?? and ?? buf->
sip_c =
1;
/* Specify Initiator Ports Capable */ buf->
atp_c =
1;
/* All Target Ports Capable */ buf->
ptpl_c =
1;
/* Persist Through Power Loss C */ buf->
tmv =
1;
/* Type Mask Valid */ * | Refer to SPC-3, Section 6.1, Tables ?? and ?? break;
/* No room left, leave now */ * | spc_cmd_pr_out -- PERSISTENT_RESERVE OUT * | Refer to SPC-3, Section 6.1, Tables ?? and ?? * Information obtained from: * Section 6.12 PERSISTENCE RESERVE OUT * Need to generate a CHECK CONDITION with ILLEGAL REQUEST * and INVALID FIELD IN CDB (0x24/0x00) if any of the following is * (1) The SERVICE ACTION field is 008h - 01fh, * (2) The reserved area in byte 1 is set, * (3) The TYPE and SCOPE fields are invalid, * (4) The reserved area in bytes 3 and 4 are set, * (5) If any of the reserved bits in the CONTROL byte are set. * Information obtained from: * Section 6.12 PERSISTENCE RESERVE OUT * Acquire ALLOCATION LENGTH from bytes 5 thru 8 * Parameter list length shall contain 24 (0x18), * the SPEC_I_PIT is zero (it is because we don't support SIP_C)) * the service action is not REGISTER AND MOVE * Information obtained from: * Section 6.11.3.3 Persistent Reservation Scope * SCOPE field shall be set to LU_SCOPE * Allocate space with an alignment that will work for any casting. * Lack of memory is not fatal, just too busy * Now request the Persistent Reserve OUT parameter list * | spc_cmd_pr_out_data -- DataIn phase of PERSISTENT_RESERVE OUT command * If this is the first time using the persistence data, * initialize the reservation and resource key queues ?
"Register & ignore existing key" * Now process the action. * PR_OUT_REGISTER_IGNORE differs from PR_OUT_REGISTER * in that the reservation_key is ignored. * PR_OUT_PREEMPT_ABORT differs from PR_OUT_PREEMPT * in that all current acitivy for the preempted * Initiators will be terminated. * PR_OUT_REGISTER_MOVE registers a key for another I_T * Check status of action performed. * Check condition required. * Handle Failed processing status * Successful, bump the PRgeneration value * If Activate Persist Through Power Loss (APTPL) is set, persist * When the last registration is removed, PGR is no longer * active and we must reset the reservation type. * Set the command dispatcher according to the reservation type * Processing is complete, release mutex * Send back a succesful response * | Refer to SPC-3, Section 6.1, Tables ?? and ?? * Validate Persistent Reserver Out parameter list * Determine if Activate Persist Trhough Power Loss (APTPL) * is valid for this device server. /* pgr - define SCSI-3 error codes */ "PGR%x LUN%d register reservation:%016lx, key:%016lx\n",
* We may need register all initiators, depending on ALL_TG_TP * The Initiator did not specify the * existing key. Reservation conflict. "old:%016lx = new:%016lx\n",
* NOTE: If we own the reservation then "old:%016lx = new:%016lx\n",
* Process request from un-registered Initiator. * Unregistered initiator is attempting /* pgr - define SCSI-3 error codes */ * Apply the last valid APTPL bit * Section 5.6.4.1 Preserving persistent reservervations and * registrations through power loss * | Refer to SPC-3, Section 6.1, Tables ?? and ?? * Do not allow an unregistered initiator to "PGR%x LUN%d reserve reservation:%016lx, key:%016lx\n",
"PGROUT: reserve service:%016lx not found\n",
* See if there is a reservation on this port by * another Initiator. There can be only one LU_SCOPE * reservation per ITL. We do not support extents. * At this point there is either no reservation or the * reservation is held by this Initiator. * An Initiator cannot re-reserve. It must first * release. But if its' type and scope match then "PGROUT reserve - transportID=%s\n" "\tkey:%016lx i_name:%s scope:%d type:%d \n",
"PGROUT reserve failed - transportID=%s\n" "\tkey:%016lx i_name:%s scope:%d type:%d \n",
* No reservation exists. Establish a new one. "PGROUT reserve - transportID=%s\n" "\tkey:%016lx i_name:%s scope:%d type:%d \n",
* | Refer to SPC-3, Section 6.1, Tables ?? and ?? * Do not allow an unregistered initiator to "PGR%x LUN%d release reservation:%016lx, key:%016lx\n",
"PGROUT: release service:%016lx not found\n",
* Releasing a non-existent reservation is allowed. "PGROUT release failed - transportID=%s\n" "\tkey:%016lx i_name:%s scope:%d type:%d \n",
* Scope and key must match to release. * Now release the reservation. "PGROUT release - transportID=%s\n" "\tkey:%016lx i_name:s scope:%d type:%d \n",
* | Refer to SPC-3, Section 6.1, Tables ?? and ?? "PGR%x LUN%d preempt reservation:%016lx, key:%016lx\n",
* Service key (preempt key) must exist, and * Initiator must be registered "PGROUT: preempt failed reservation:%016lx, key:%016lx\n",
* Preempt all keys matching service action key and free * the associated structures. Do not set UNIT_ATTN for * the Initiator which requested the action. * Unlike the other Persistent Reservation commands, the preempt, * preempt_and_abort and clear actions are service delivery port * independent. So we remove matching keys across ports. * Get next pointer in case the key gets deallocated /* Skip non-matching keys */ "PGROUT preempt key:%016lx != key:%016lx " * Determine if UNIT ATTN needed * Remove the registration key "PGROUT preempt delete key:%016lx " "i_name:%s transportID:%s\n",
* Do not set UNIT ATTN for calling Initiator * Is this the preempt and abort? * Find associated I_T Nexuses * Re-establish our service key if we preempted it. "PGROUT: preempt - register:%016lx, i_name:%s:%s\n",
* Now look for a matching reservation to preempt. * Get next pointer in case the reservation gets deallocated /* Skip non-matching keys */ "PGROUT preempt rsrv:%016lx != rsrv:%016lx" * Remove matching reservations on other ports * and establish a new reservation on this port only. * To change the fuctionality to preempt rather than * delete the reservations on other ports just remove * the following block of code. "PGROUT preempt(-) rsrv:%016lx " "i_name:%s scope:%d type:%d \n",
* We have a matching reservation so preempt it. "PGROUT preempt(+) rsrv:%016lx " "i_name:%s scope:%d type:%d \n",
* | Refer to SPC-3, Section 6.1, Tables ?? and ?? * Do not allow an unregistered initiator to attempting to "PGR%x LUN%d clear reservation:%016lx, key:%016lx\n",
"PGROUT: clear service:%016lx not found\n",
* We need to set UNIT ATTENTION for all registered initiators. /* Do not set UNIT ATTN for calling Initiator */ * At this point the only way to get in here is to be the owner * Now erase the reservation and registration info. * | spc_pr_out_register_and_move * | Refer to SPC-3, Section 6.1, Tables ?? and ?? * | Allocate a new registration key and add it to the key list. * | Refer to SPC-3, Section 6.1, Tables ?? and ?? * | Initialize registration & reservervation queues * | Free a registration key * | Find a registration key based on the key, owner id and port id. * | Allocate a new reservation and add it to the rsrv list. * | Find a reservation based on the key, owner id and port id. * | Find specified key / reservation and erease it * | spc_pr_rsrv_release - * | Release the reservation the perform any other required clearing actions. * | Refer to SPC-3, Section 6.1, Tables ?? and ?? * For Registrants-Only mode set UNIT ATTN. * No UNIT ATTN for the requesting Initiator. * Find associated I_T Nexuses * Remove the reservation. * | Read in pgr keys and reservations for this device from backend storage. * | At least the local pgr write lock must be held. * Open the PERSISTENCE file specification if one exists * taking into account the alternate location if a ZVOL * Clean up on no persistence file found * If this is the first time using the persistence data, * initialize the reservation and resource key queues * Perform some vailidation on what we are looking at * Was the key previously read, if not restore it * Get the PGR reservations * Was the reservation previously read, if not restore it * If there was data then set the reservation type. * Set the command dispatcher according to the reservation type * | Write PGR keys and reservations for this device to backend storage. * | At least the local pgr write lock must be held. * Verify space requirements and allocate buffer memory. * Space needed is header + keylist + rsrvlist. * Subtract 1 from numkeys since header already defines * the first element of the keylist. * Round up the bufsize to the next FBA boundary. * Open the PERSISTENCE file specification if one exists * taking into account the alternate location if a ZVOL