Mercurial > illumos > illumos-gate
changeset 5044:366fa13eb032
6415440 iSCSI target needs persistent reserve support
line wrap: on
line diff
--- a/deleted_files/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c Thu Sep 13 13:50:11 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1913 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * []------------------------------------------------------------------[] - * | Implementation of SPC-3 Persistent Reserve emulation | - * []------------------------------------------------------------------[] - */ -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/asynch.h> -#include <sys/param.h> -#include <sys/sysmacros.h> -#include <strings.h> -#include <unistd.h> -#include <pthread.h> -#include <assert.h> - -#include <sys/scsi/generic/sense.h> -#include <sys/scsi/generic/status.h> -#include <sys/scsi/generic/inquiry.h> -#include <sys/scsi/generic/mode.h> -#include <sys/scsi/generic/commands.h> -#include <sys/scsi/generic/persist.h> - -#include "t10.h" -#include "t10_spc.h" -#include "t10_spc_pr.h" -#include "t10_sbc.h" -#include "target.h" - -/* - * External declarations - */ -void spc_free(emul_handle_t id); -void sbc_cmd(t10_cmd_t *, uint8_t *, size_t); -void sbc_cmd_reserved(t10_cmd_t *, uint8_t *, size_t); - -extern target_queue_t *mgmtq; - -/* - * Forward declarations - */ -static - spc_pr_rsrv_t *spc_pr_rsrv_find(scsi3_pgr_t *, uint64_t, uint64_t, char *); -static - spc_pr_rsrv_t *spc_pr_rsrv_alloc(scsi3_pgr_t *, uint64_t, uint64_t, char *, - uint8_t, uint8_t); -static - spc_pr_key_t *spc_pr_key_find(scsi3_pgr_t *, uint64_t, uint64_t, char *); -static - spc_pr_key_t *spc_pr_key_alloc(scsi3_pgr_t *, uint64_t, uint64_t, char *); - -static void spc_pr_rsrv_release(t10_cmd_t *, scsi3_pgr_t *, spc_pr_rsrv_t *); -static void spc_pr_key_free(scsi3_pgr_t *, spc_pr_key_t *); -static void spc_pr_rsrv_free(scsi3_pgr_t *, spc_pr_rsrv_t *); -static void spc_pr_erase(scsi3_pgr_t *); -static void spc_pr_key_rsrv_init(scsi3_pgr_t *); - -static int spc_pr_register(t10_cmd_t *, void *, size_t); -static int spc_pr_reserve(t10_cmd_t *, void *, size_t); -static int spc_pr_release(t10_cmd_t *, void *, size_t); -static int spc_pr_clear(t10_cmd_t *, void *, size_t); -static int spc_pr_preempt(t10_cmd_t *, void *, size_t); -static int spc_pr_register_and_move(t10_cmd_t *, void *, size_t); - -static int spc_pr_in_readkeys(char *, scsi3_pgr_t *, void *, uint16_t); -static int spc_pr_in_readrsrv(char *, scsi3_pgr_t *, void *, uint16_t); -static int spc_pr_in_repcap(char *, scsi3_pgr_t *, void *, uint16_t); -static int spc_pr_in_fullstat(char *, scsi3_pgr_t *, void *, uint16_t); - -static int spc_pgr_isconflict(uint8_t *, uint_t); -Boolean_t spc_pr_write(t10_cmd_t *); - -/* - * []---- - * | spc_pgr_check -- PERSISTENT_RESERVE {IN|OUT} check of I_T_L - * | Refer to SPC-3, Section ?.?, Tables ?? and ?? - * []---- - */ -Boolean_t -spc_pgr_check(t10_cmd_t *cmd, uint8_t *cdb) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_rsrv_t *rsrv; - Boolean_t conflict = False; - - /* - * Check reservation commands. - */ - switch (cdb[0]) { - /* - * Always dis-allow these commands. - */ - case SCMD_RESERVE: - case SCMD_RESERVE_G1: - case SCMD_RELEASE: - case SCMD_RELEASE_G1: - conflict = True; - goto done; - - /* - * Always allow these commands. - */ - case SCMD_PERSISTENT_RESERVE_IN: - case SCMD_PERSISTENT_RESERVE_OUT: - conflict = False; - goto done; - } - - /* - * If no reservations exist, allow all remaining command types. - */ - assert(res->res_type == RT_PGR); - if (pgr->pgr_numrsrv == 0) { - conflict = False; - goto done; - } - - /* - * 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. - */ - if (!(rsrv = spc_pr_rsrv_find(pgr, 0, 0, T10_PGR_TID(cmd)))) { - queue_prt(mgmtq, Q_PR_IO, "PGR Reserved on other port\n", - "\t%016x:%s\n", T10_PGR_ISID(cmd), T10_PGR_TID(cmd)); - conflict = True; - goto done; - } - - /* - * Check the command against the reservation type for this port. - */ - switch (rsrv->r_type) { - case PGR_TYPE_WR_EX: - case PGR_TYPE_EX_AC: - if (T10_PGR_ISID(cmd) == rsrv->r_isid) - conflict = False; - else - conflict = spc_pgr_isconflict(cdb, - rsrv->r_type); - break; - case PGR_TYPE_WR_EX_RO: - case PGR_TYPE_EX_AC_RO: - if (spc_pr_key_find( - pgr, 0, T10_PGR_ISID(cmd), T10_PGR_TID(cmd))) - conflict = False; - else - conflict = spc_pgr_isconflict(cdb, - rsrv->r_type); - break; - case PGR_TYPE_WR_EX_AR: - case PGR_TYPE_EX_AC_AR: - if (spc_pr_key_find(pgr, 0, 0, T10_PGR_TID(cmd))) - conflict = False; - else - conflict = spc_pgr_isconflict(cdb, - rsrv->r_type); - break; - default: - conflict = True; - break; - } - -done: - queue_prt(mgmtq, Q_PR_IO, "PGR%d LUN%d CDB:%s - spc_pgr_check(%s)\n", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL - ? "(no name)" - : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name, - (conflict) ? "Conflict" : "Allowed"); - - return (conflict); -} - -/* - * []---- - * | spc_pgr_isconflict - * | PGR reservation conflict checking. - * | SPC-3, Revision 23, Table 31 - * []---- - */ -static int -spc_pgr_isconflict(uint8_t *cdb, uint_t type) -{ - Boolean_t conflict = False; - - switch (cdb[0]) { - case SCMD_FORMAT: - case SCMD_EXTENDED_COPY: - case SCMD_LOG_SELECT_G1: - case SCMD_MODE_SELECT: - case SCMD_MODE_SELECT_G1: - case SCMD_MODE_SENSE: - case SCMD_MODE_SENSE_G1: - case SCMD_READ_ATTRIBUTE: - case SCMD_READ_BUFFER: - case SCMD_GDIAG: /* SCMD_RECEIVE_DIAGNOSTIC_RESULTS */ - case SCMD_SDIAG: /* SCMD_SEND_DIAGNOSTIC_RESULTS */ - case SCMD_WRITE_ATTRIBUTE: - case SCMD_WRITE_BUFFER: - conflict = True; - break; - - case SCMD_DOORLOCK: /* SCMD_PREVENT_ALLOW_MEDIA_REMOVAL */ - /* - * As per SPC-3, Revision 23, Table 31 - * (prevent <> 0) - */ - conflict = (cdb[4] & 0x1) ? True: False; - break; - - case SCMD_REPORT_TARGET_PORT_GROUPS: /* SCMD_REPORT_ */ - /* - * As pee SPC-3, Revision 23, Section 6.23 - */ - switch ((cdb[1] & 0x03)) { - /* SCMD_REPORT_SUPPORTED_OPERATION_CODES */ - case 0x0c: - /* SCMD_REPORT_SUPPORTED_MANAGEMENT_FUNCTIONS */ - case 0x0d: - - conflict = True; - break; - } - break; - - case SCMD_SET_DEVICE: - /* - * SPC-3, Revision 23, Section 6.29 - */ - switch ((cdb[1] & 0x1F)) { - case SCMD_SET_DEVICE_IDENTIFIER: - case SCMD_SET_PRIORITY: - case SCMD_SET_TARGET_PORT_GROUPS: - case SCMD_SET_TIMESTAMP: - conflict = True; - break; - } - break; - - case SCMD_READ: - case SCMD_READ_G1: - case SCMD_READ_G4: - if (type == PGR_TYPE_EX_AC || type == PGR_TYPE_EX_AC_RO) - conflict = True; - break; - } - - return (conflict); -} - - -/* - * []---- - * | spc_cmd_pr_in -- PERSISTENT_RESERVE IN - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/*ARGSUSED*/ -void -spc_cmd_pr_in(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - scsi_cdb_prin_t *p_prin = (scsi_cdb_prin_t *)cdb; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - uint16_t alen; - size_t len; - void *buf; - Boolean_t status; - - /* - * Information obtained from: - * SPC-3, Revision 23 - * 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 - * true. - * (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. - */ - if ((p_prin->action >= 0x4) || p_prin->resbits || p_prin->resbytes[0] || - p_prin->resbytes[1] || p_prin->resbytes[2] || p_prin->resbytes[3] || - p_prin->resbytes[4] || p_prin->control) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Information obtained from: - * SPC-3, Revision 23 - * 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. - */ - if ((alen = SCSI_READ16(p_prin->alloc_len)) == 0) { - queue_prt(mgmtq, Q_PR_IO, - "PGR:%d LUN:%d CDB:%s - spc_cmd_pr_in, len = 0\n", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL - ? "(no name)" - : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name); - - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - /* - * Allocate space with an alignment that will work for any casting. - */ - if ((buf = memalign(sizeof (void *), alen)) == NULL) { - /* - * Lack of memory is not fatal, just too busy - */ - trans_send_complete(cmd, STATUS_BUSY); - return; - } else { - bzero(buf, alen); - } - - /* - * Start processing, lock reservation - */ - pthread_rwlock_rdlock(&res->res_rwlock); - - /* - * Per SPC-3, Revision 23, Table 102, validate ranget of service actions - */ - switch (p_prin->action) { - case PR_IN_READ_KEYS: - len = spc_pr_in_readkeys( - T10_PGR_TID(cmd), pgr, buf, alen); - break; - case PR_IN_READ_RESERVATION: - len = spc_pr_in_readrsrv( - T10_PGR_TID(cmd), pgr, buf, alen); - break; - case PR_IN_REPORT_CAPABILITIES: - len = spc_pr_in_repcap( - T10_PGR_TID(cmd), pgr, buf, alen); - break; - case PR_IN_READ_FULL_STATUS: - len = spc_pr_in_fullstat( - T10_PGR_TID(cmd), pgr, buf, alen); - break; - default: - pthread_rwlock_unlock(&res->res_rwlock); - spc_free(buf); - - /* - * Fail command - */ - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Complete processing, unlock reservation - */ - pthread_rwlock_unlock(&res->res_rwlock); - - /* - * Now send the selected Persistent Reservation response back - */ - if (trans_send_datain(cmd, buf, alen, 0, spc_free, True, buf) == False) - trans_send_complete(cmd, STATUS_BUSY); -} - -/* - * []---- - * | spc_pr_in_readkey - - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static int -spc_pr_in_readkeys(char *transportID, scsi3_pgr_t *pgr, void *bp, - uint16_t alloc_len) -{ - int i = 0, max_buf_keys, hsize; - scsi_prin_readrsrv_t *buf = (scsi_prin_readrsrv_t *)bp; - spc_pr_key_t *key; - - hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len); - max_buf_keys = ((int)alloc_len - hsize) / sizeof (key->k_key); - - queue_prt(mgmtq, Q_PR_IO, - "PGRIN readkeys - transportID=%s\n", transportID); - - if (pgr->pgr_numkeys) - for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - key != (spc_pr_key_t *)&pgr->pgr_keylist; - key = (spc_pr_key_t *)key->k_link.lnk_fwd) { - - if (strcmp(key->k_transportID, transportID)) - continue; - - if (i < max_buf_keys) - SCSI_WRITE64(buf->res_key_list[i].reservation_key, - key->k_key); - - queue_prt(mgmtq, Q_PR_IO, - "PGRIN readkeys - key:%016x, isid:%016x\n", - key->k_key, key->k_isid); - - i++; - } - - SCSI_WRITE32(buf->add_len, i * sizeof (key->k_key)); - SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation); - - return (hsize + min(SCSI_READ32(buf->add_len), - (int)(max_buf_keys * sizeof (key->k_key)))); -} - -/* - * []---- - * | spc_pr_in_readresv - - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static int -spc_pr_in_readrsrv( - char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len) -{ - int i = 0, max_buf_rsrv, hsize; - spc_pr_rsrv_t *rsrv; - scsi_prin_readrsrv_t *buf = (scsi_prin_readrsrv_t *)bp; - - hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len); - max_buf_rsrv = ((int)alloc_len - hsize) / sizeof (scsi_prin_rsrvdesc_t); - - queue_prt(mgmtq, Q_PR_IO, - "PGRIN readrsrv - transportID=%s\n", transportID); - - if (pgr->pgr_numrsrv) - for (rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; - rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; - rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd) { - - if (strcmp(rsrv->r_transportID, transportID)) - continue; - - if (i < max_buf_rsrv) { - SCSI_WRITE64(buf->res_key_list[i].reservation_key, - rsrv->r_key); - buf->res_key_list[i].scope = rsrv->r_scope; - buf->res_key_list[i].type = rsrv->r_type; - } - - queue_prt(mgmtq, Q_PR_IO, - "PGRIN readrsrv - " - "key:%016x isid:%016x scope:%d type:%d \n", - rsrv->r_key, rsrv->r_isid, rsrv->r_scope, rsrv->r_type); - - i++; - } - - SCSI_WRITE32(buf->add_len, i * sizeof (scsi_prin_rsrvdesc_t)); - SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation); - - return (hsize + min(SCSI_READ32(buf->add_len), - (int)(max_buf_rsrv * sizeof (scsi_prin_rsrvdesc_t)))); -} - -/* - * []---- - * | spc_pr_in_repcap - - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/* - */ -static int -spc_pr_in_repcap( - char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len) -{ - scsi_prin_rpt_cap_t *buf = (scsi_prin_rpt_cap_t *)bp; - - buf->crh = 0; /* Supports Reserve / Release */ - 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 */ - buf->ptpl_a = pgr_persist; /* Persist Though Power Loss Active */ - buf->pr_type.wr_ex = 1; /* Write Exclusve */ - buf->pr_type.ex_ac = 1; /* Exclusive Access */ - buf->pr_type.wr_ex_ro = 1; /* Write Exclusive Registrants Only */ - buf->pr_type.ex_ac_ro = 1; /* Exclusive Access Registrants Only */ - buf->pr_type.wr_ex_ar = 1; /* Write Exclusive All Registrants */ - buf->pr_type.ex_ac_ar = 1; /* Exclusive Access All Registrants */ - - SCSI_WRITE16(buf->length, sizeof (scsi_prin_rpt_cap_t)); - - return (sizeof (scsi_prin_rpt_cap_t)); -} - -/* - * []---- - * | spc_pr_in_fullstat - - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/* - */ -static int -spc_pr_in_fullstat( - char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len) -{ - int i = 0, max_buf_rsrv, hsize; - spc_pr_rsrv_t *rsrv; - scsi_prin_full_status_t *buf = (scsi_prin_full_status_t *)bp; - - hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len); - max_buf_rsrv = ((int)alloc_len - hsize) / - sizeof (scsi_prin_full_status_t); - - if (pgr->pgr_numrsrv) - for (i = 0, rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; - rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; - rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd) { - - if (i < max_buf_rsrv) { - SCSI_WRITE64(buf->full_desc[i].reservation_key, - rsrv->r_key); - buf->full_desc[i].all_tg_pt = 1; - buf->full_desc[i].r_holder = - strcmp(rsrv->r_transportID, transportID) ? 0 : 1; - buf->full_desc[i].scope = rsrv->r_scope; - buf->full_desc[i].type = rsrv->r_type; - SCSI_WRITE16(buf->full_desc[i].rel_tgt_port_id, 0); - SCSI_WRITE32(buf->full_desc[i].add_len, - sizeof (scsi_transport_id_t)); - buf->full_desc[i].trans_id.protocol_id = - iSCSI_PROTOCOL_ID; - buf->full_desc[i].trans_id.format_code = - WW_UID_DEVICE_NAME; - SCSI_WRITE16(buf->full_desc[i].trans_id.add_len, 0); - sprintf(buf->full_desc[i].trans_id.iscsi_name, ""); - } - - i++; - } - - SCSI_WRITE32(buf->add_len, i * sizeof (scsi_prin_rsrvdesc_t)); - SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation); - - return (hsize + min(SCSI_READ32(buf->add_len), - (int)(max_buf_rsrv * sizeof (scsi_prin_rsrvdesc_t)))); - -} - -/* - * []---- - * | spc_cmd_pr_out -- PERSISTENT_RESERVE OUT - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/*ARGSUSED*/ -void -spc_cmd_pr_out(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cdb; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - size_t len; - void *buf; - - /* - * Information obtained from: - * SPC-3, Revision 23 - * 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 - * true. - * (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. - */ - if ((p_prout->action >= 0x8) || p_prout->resbits || - (p_prout->type >= 0x9) || - (p_prout->scope >= 0x3) || p_prout->control) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.12 PERSISTENCE RESERVE OUT - * Acquire ALLOCATION LENGTH from bytes 5 thru 8 - */ - len = SCSI_READ32(p_prout->param_len); - - /* - * 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 - */ - if ((p_prout->action != PR_OUT_REGISTER_MOVE) && (len != 24)) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_PARAM_LIST_LEN, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11.3.3 Persistent Reservation Scope - * SCOPE field shall be set to LU_SCOPE - */ - if (p_prout->scope != PR_LU_SCOPE) { - pthread_rwlock_unlock(&res->res_rwlock); - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Allocate space with an alignment that will work for any casting. - */ - if ((buf = memalign(sizeof (void *), len)) == NULL) { - /* - * Lack of memory is not fatal, just too busy - */ - trans_send_complete(cmd, STATUS_BUSY); - return; - } - - /* - * Now request the Persistent Reserve OUT parameter list - */ - if (trans_rqst_dataout(cmd, buf, len, 0, buf, spc_free) == False) - trans_send_complete(cmd, STATUS_BUSY); -} - -/* - * []---- - * | spc_cmd_pr_out_data -- DataIn phase of PERSISTENT_RESERVE OUT command - * []---- - */ -/*ARGSUSED*/ -void -spc_cmd_pr_out_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - t10_lu_impl_t *lu; - int status; - - /* - * If this is the first time using the persistance data, - * initialize the reservation and resource key queues - */ - pthread_rwlock_wrlock(&res->res_rwlock); - if (pgr->pgr_rsrvlist.lnk_fwd == NULL) { - spc_pr_key_rsrv_init(pgr); - } - - /* - * Now process the action. - */ - switch (p_prout->action) { - case PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY: - case PR_OUT_REGISTER: - /* - * PR_OUT_REGISTER_IGNORE differs from PR_OUT_REGISTER - * in that the reservation_key is ignored. - */ - status = spc_pr_register(cmd, data, data_len); - break; - - case PR_OUT_RESERVE: - status = spc_pr_reserve(cmd, data, data_len); - break; - - case PR_OUT_RELEASE: - status = spc_pr_release(cmd, data, data_len); - break; - - case PR_OUT_CLEAR: - status = spc_pr_clear(cmd, data, data_len); - break; - - case PR_OUT_PREEMPT_ABORT: - case PR_OUT_PREEMPT: - /* - * PR_OUT_PREEMPT_ABORT differs from PR_OUT_PREEMPT - * in that all current acitivy for the preempted - * Initiators will be terminated. - */ - status = spc_pr_preempt(cmd, data, data_len); - break; - - case PR_OUT_REGISTER_MOVE: - /* - * PR_OUT_REGISTER_MOVE registers a key for another I_T - */ - status = spc_pr_register_and_move(cmd, data, data_len); - break; - } - - /* - * Check status of action performed. - */ - if (status == STATUS_CHECK) { - /* - * Check condition required. - */ - pthread_rwlock_unlock(&res->res_rwlock); - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, cmd->c_lu->l_asc, cmd->c_lu->l_ascq); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Handle Failed processing status - */ - if (status != STATUS_GOOD) { - pthread_rwlock_unlock(&res->res_rwlock); - trans_send_complete(cmd, status); - return; - } - - /* - * Successful, bump the PRgeneration value - */ - if (p_prout->action != PR_OUT_RESERVE && - p_prout->action != PR_OUT_RELEASE) - pgr->pgr_generation++; - - /* - * If Activate Persist Through Power Loss (APTPL) is set, persist - * this PGR data on disk - */ - if (plist->aptpl || pgr->pgr_aptpl) - spc_pr_write(cmd); - - /* - * When the last registration is removed, PGR is no longer - * active and we must reset the reservation type. - */ - if (pgr->pgr_numkeys == 0 && pgr->pgr_numrsrv == 0) { - res->res_type = RT_NONE; - pgr->pgr_aptpl = 0; - } else { - res->res_type = RT_PGR; - } - - /* - * Set the command dispatcher according to the reservation type - */ - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_cmd = (res->res_type == RT_NONE) - ? sbc_cmd - : sbc_cmd_reserved; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - - queue_prt(mgmtq, Q_PR_IO, "PGROUT:%d LUN:%d action:%s\n", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - (p_prout->action == PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY) - ? "Register & ignore existing key" - : (p_prout->action == PR_OUT_REGISTER) - ? "Register" - : (p_prout->action == PR_OUT_RESERVE) - ? "Reserve" - : (p_prout->action == PR_OUT_RELEASE) - ? "Release" - : (p_prout->action == PR_OUT_CLEAR) - ? "Clear" - : (p_prout->action == PR_OUT_PREEMPT_ABORT) - ? "Preempt & abort" - : (p_prout->action == PR_OUT_PREEMPT) - ? "Preempt" - : (p_prout->action == PR_OUT_REGISTER_MOVE) - ? "Register & move" - : "Uknown"); - - /* - * Processing is complete, release mutex - */ - pthread_rwlock_unlock(&res->res_rwlock); - - /* - * Send back a succesful response - */ - trans_send_complete(cmd, STATUS_GOOD); -} - -/* - * []---- - * | spc_pr_register - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static int -spc_pr_register(t10_cmd_t *cmd, void *data, size_t data_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_rsrv_t *rsrv; - spc_pr_key_t *key; - uint64_t reservation_key; - uint64_t service_key; - t10_lu_impl_t *lu; - t10_targ_impl_t *ti; - - /* - * Validate Persistent Reserver Out parameter list - */ - if (plist->obsolete1[0] || plist->obsolete1[1] || - plist->obsolete1[2] || plist->obsolete1[3] || - plist->resbits1 || plist->resbits2 || plist->resbytes1 || - plist->obsolete2[0] || plist->obsolete2[1]) { - cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST; - cmd->c_lu->l_asc = SPC_ASC_INVALID_CDB; - cmd->c_lu->l_ascq = 0; - return (STATUS_CHECK); - } - - /* - * Determine if Activate Persist Trhough Power Loss (APTPL) - * is valid for this device server. - */ - if (plist->aptpl && (pgr_persist == 0)) { - /* pgr - define SCSI-3 error codes */ - cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST; - cmd->c_lu->l_asc = SPC_ASC_INVALID_FIELD_IN_PARAMETER_LIST; - cmd->c_lu->l_ascq = 0; - return (STATUS_CHECK); - } - - /* - * Get reservation values - */ - reservation_key = SCSI_READ64(plist->reservation_key); - service_key = SCSI_READ64(plist->service_key); - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: register reservation:%016x, key:%016x\n", - reservation_key, service_key); - - /* - * We may need register all initiators, depending on ALL_TG_TP - */ - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - /* - * Find specified key - */ - ti = lu->l_targ; - key = spc_pr_key_find(pgr, 0, ti->s_isid, ti->s_transportID); - if (key) { - /* - * What about ALL_TG_TP? - */ - if (plist->all_tg_pt || - (key->k_isid == T10_PGR_ISID(cmd))) { - - if (p_prout->action == PR_OUT_REGISTER && - key->k_key != reservation_key) { - /* - * The Initiator did not specify the - * existing key. Reservation conflict. - */ - return (STATUS_RESERVATION_CONFLICT); - } - /* - * Change existing key ? - */ - if (service_key) { - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: change " - "old:%016x = new:%016x\n", - key->k_key, service_key); - - /* - * Overwrite (change) key - */ - key->k_key = service_key; - - } else { - /* - * Remove existing key - * NOTE: If we own the reservation then - * we must release it. - */ - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: delete " - "old:%016x = new:%016x\n", - key->k_key, service_key); - - rsrv = spc_pr_rsrv_find(pgr, 0, - ti->s_isid, ti->s_transportID); - if (rsrv) { - spc_pr_rsrv_release( - cmd, pgr, rsrv); - spc_pr_key_free(pgr, key); - } - } - } - } else { - /* - * What about ALL_TG_TP? - */ - if (plist->all_tg_pt || - (ti->s_isid == T10_PGR_ISID(cmd))) { - /* - * Process request from un-registered Initiator. - */ - if ((p_prout->action == PR_OUT_REGISTER) && - (reservation_key || service_key == 0)) { - /* - * Unregistered initiator is attempting - * to modify a key. - */ - return (STATUS_RESERVATION_CONFLICT); - } - - /* - * Allocate new key. - */ - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: new:%016x\n", service_key); - - key = spc_pr_key_alloc(pgr, service_key, - ti->s_isid, ti->s_transportID); - if (key == NULL) { - /* pgr - define SCSI-3 error codes */ - cmd->c_lu->l_status = - KEY_ABORTED_COMMAND; - cmd->c_lu->l_asc = - SPC_ASC_MEMORY_OUT_OF; - cmd->c_lu->l_ascq = - SPC_ASCQ_RESERVATION_FAIL; - return (STATUS_CHECK); - } - } - } - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - - /* - * Apply the last valid APTPL bit - * SPC-3, Revision 23 - * Section 5.6.4.1 Preserving persistent reservervations and - * registrations through power loss - */ - pgr->pgr_aptpl = plist->aptpl; - - return (STATUS_GOOD); -} - -/* - * []---- - * | spc_pr_reserve - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/* ARGSUSED */ -static int -spc_pr_reserve(t10_cmd_t *cmd, void *data, size_t data_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_rsrv_t *rsrv; - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - uint64_t reservation_key; - int status; - - /* - * Do not allow an unregistered initiator to - * make a reservation. - */ - reservation_key = SCSI_READ64(plist->reservation_key); - if (!spc_pr_key_find( - pgr, reservation_key, T10_PGR_ISID(cmd), T10_PGR_TID(cmd))) { - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: reserve reservation:%016x not found\n", - reservation_key); - - return (STATUS_RESERVATION_CONFLICT); - } else { - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: reserve reservation:%016x\n", reservation_key); - - } - - /* - * 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. - */ - if (rsrv = spc_pr_rsrv_find(pgr, 0, 0, T10_PGR_TID(cmd))) { - if (rsrv->r_isid != T10_PGR_ISID(cmd)) { - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: reserve %016x != %016x:%s\n", - rsrv->r_isid, T10_PGR_ISID(cmd), - T10_PGR_TID(cmd)); - - return (STATUS_RESERVATION_CONFLICT); - } - } - - /* - * At this point there is either no reservation or the - * reservation is held by this Initiator. - */ - if (rsrv != NULL) { - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT reserve(+) - transportID=%s\n" - "\tkey:%016x isid:%016x scope:%d type:%d \n", - rsrv->r_transportID, rsrv->r_key, rsrv->r_isid, - rsrv->r_scope, rsrv->r_type); - - /* - * An Initiator cannot re-reserve. It must first - * release. But if its' type and scope match then - * return STATUS_GOOD. - */ - if (rsrv->r_type == p_prout->type && - rsrv->r_scope == p_prout->scope) { - status = STATUS_GOOD; - } else { - status = STATUS_RESERVATION_CONFLICT; - } - } else { - /* - * No reservation exists. Establish a new one. - */ - queue_prt(mgmtq, Q_PR_IO, - "PGROUT reserve - transportID=%s\n" - "\tkey:%016x isid:%016x scope:%d type:%d \n", - T10_PGR_TID(cmd), reservation_key, T10_PGR_ISID(cmd), - p_prout->scope, p_prout->type); - - rsrv = spc_pr_rsrv_alloc(pgr, reservation_key, - T10_PGR_ISID(cmd), T10_PGR_TID(cmd), - p_prout->scope, p_prout->type); - if (rsrv == NULL) { - cmd->c_lu->l_status = KEY_ABORTED_COMMAND; - cmd->c_lu->l_asc = SPC_ASC_MEMORY_OUT_OF; - cmd->c_lu->l_ascq = SPC_ASCQ_RESERVATION_FAIL; - status = STATUS_CHECK; - } else { - status = STATUS_GOOD; - } - } - - return (status); -} - -/* - * []---- - * | spc_pr_release - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static int -spc_pr_release(t10_cmd_t *cmd, void *data, size_t data_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_rsrv_t *rsrv; - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - uint64_t reservation_key; - int status; - - /* - * Do not allow an unregistered initiator to attempting to - * release a reservation. - */ - reservation_key = SCSI_READ64(plist->reservation_key); - if (!spc_pr_key_find( - pgr, reservation_key, T10_PGR_ISID(cmd), T10_PGR_TID(cmd))) { - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: release reservation:%016x not found\n", - reservation_key); - - return (STATUS_RESERVATION_CONFLICT); - } else { - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: release reservation:%016x\n", reservation_key); - } - - if (!(rsrv = spc_pr_rsrv_find( - pgr, 0, T10_PGR_ISID(cmd), T10_PGR_TID(cmd)))) { - /* - * Releasing a non-existent reservation is allowed. - */ - status = STATUS_GOOD; - - } else if (p_prout->scope != rsrv->r_scope || - p_prout->type != rsrv->r_type || - reservation_key != rsrv->r_key) { - queue_prt(mgmtq, Q_PR_IO, - "PGROUT release failed - transportID=%s\n" - "\tkey:%016x isid:%016x scope:%d type:%d \n", - T10_PGR_TID(cmd), reservation_key, T10_PGR_ISID(cmd), - p_prout->scope, p_prout->type); - - /* - * Scope and key must match to release. - */ - cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST; - cmd->c_lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; - cmd->c_lu->l_ascq = SPC_ASCQ_RES_RELEASED; - status = STATUS_CHECK; - } else { - /* - * Now release the reservation. - */ - queue_prt(mgmtq, Q_PR_IO, - "PGROUT release - transportID=%s\n" - "\tkey:%016x isid:%016x scope:%d type:%d \n", - rsrv->r_transportID, rsrv->r_key, rsrv->r_isid, - rsrv->r_scope, rsrv->r_type); - - spc_pr_rsrv_release(cmd, pgr, rsrv); - status = STATUS_GOOD; - } - - return (status); -} - -/* - * []---- - * | spc_pr_preempt - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/* ARGSUSED */ -static int -spc_pr_preempt(t10_cmd_t *cmd, void *data, size_t data_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; - t10_lu_impl_t *lu; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - uint64_t reservation_key; - uint64_t service_key; - spc_pr_key_t *key; - spc_pr_rsrv_t *rsrv; - int status = STATUS_GOOD; - - /* - * Get reservation values - */ - reservation_key = SCSI_READ64(plist->reservation_key); - service_key = SCSI_READ64(plist->service_key); - - - /* - * Initiator must be registered and service key (preempt key) - * must exist. - */ - if ((!(key = spc_pr_key_find(pgr, service_key, 0, ""))) || - (!(rsrv = spc_pr_rsrv_find(pgr, reservation_key, - T10_PGR_ISID(cmd), "")))) { - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: preempt failed reservation:%016x, key:%016x\n", - reservation_key, service_key); - - return (STATUS_RESERVATION_CONFLICT); - } else { - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: preempt reservation:%016x, key:%016x\n", - reservation_key, service_key); - } - - /* - * 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. - */ - for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - key != (spc_pr_key_t *)&pgr->pgr_keylist; - key = (spc_pr_key_t *)key->k_link.lnk_fwd) { - - /* Skip non-matching keys */ - if (key->k_key != service_key) - continue; - - /* Remove the registration key. */ - spc_pr_key_free(pgr, key); - - /* Do not set UNIT ATTN for calling Initiator */ - if (key->k_isid == T10_PGR_ISID(cmd)) - continue; - - /* - * Find associated I_T Nexuses - */ - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_cmd = sbc_cmd; - lu->l_status = KEY_UNIT_ATTENTION; - lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; - lu->l_ascq = SPC_ASCQ_RES_PREEMPTED; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - - /* - * Is this the preempt and abort? - */ - if (p_prout->action == PR_OUT_PREEMPT_ABORT) { - queue_message_set( - cmd->c_lu->l_common->l_from_transports, - Q_HIGH, msg_reset_lu, (void *)cmd->c_lu); - } - } - - /* - * Re-establish our registration key if we preempted it. - */ - if (!(key = spc_pr_key_find( - pgr, reservation_key, T10_PGR_ISID(cmd), T10_PGR_TID(cmd)))) { - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: preempt - register:%016x, isid:%016x:%s\n", - reservation_key, T10_PGR_ISID(cmd), T10_PGR_TID(cmd)); - - key = spc_pr_key_alloc(pgr, reservation_key, - T10_PGR_ISID(cmd), T10_PGR_TID(cmd)); - } - - /* - * Now look for a matching reservation to preempt. - */ - for (rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; - rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; - rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd) { - - /* Skip non-matching keys */ - if (rsrv->r_key != service_key) - continue; - - /* - * 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. - */ - if (strcmp(rsrv->r_transportID, T10_PGR_TID(cmd))) { - spc_pr_rsrv_free(pgr, rsrv); - continue; - } - - rsrv->r_key = reservation_key; - rsrv->r_isid = T10_PGR_ISID(cmd); - rsrv->r_scope = p_prout->scope; - rsrv->r_type = p_prout->type; - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT preempt - transportID=%s\n" - "\tkey:%016x isid:%016x scope:%d type:%d \n", - rsrv->r_transportID, rsrv->r_key, rsrv->r_isid, - rsrv->r_scope, rsrv->r_type); - } - - return (status); -} - -/* - * []---- - * | spc_pr_clear - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/* ARGSUSED */ -static int -spc_pr_clear(t10_cmd_t *cmd, void *data, size_t data_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - uint64_t reservation_key; - spc_pr_key_t *key; - t10_targ_impl_t *tp; - t10_lu_impl_t *lu; - - /* - * Do not allow an unregistered initiator to attempting to - * clear the PGR. - */ - reservation_key = SCSI_READ64(plist->reservation_key); - if (!spc_pr_key_find(pgr, reservation_key, T10_PGR_ISID(cmd), "")) { - - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: clear pgr:%016x not found\n", reservation_key); - - return (STATUS_RESERVATION_CONFLICT); - } else { - queue_prt(mgmtq, Q_PR_IO, - "PGROUT: clear pgr:%016x\n", reservation_key); - } - - /* - * We need to set UNIT ATTENTION for all registered initiators. - */ - for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - key != (spc_pr_key_t *)&pgr->pgr_keylist; - key = (spc_pr_key_t *)key->k_link.lnk_fwd) { - - /* Do not set UNIT ATTN for calling Initiator */ - if (key->k_isid == T10_PGR_ISID(cmd)) - continue; - /* - * At this point the only way to get in here is to be the owner - * of the reservation. - */ - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_status = KEY_UNIT_ATTENTION; - lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; - lu->l_ascq = SPC_ASCQ_RES_PREEMPTED; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - } - - /* - * Now erase the reservation and registration info. - */ - spc_pr_erase(pgr); - - return (STATUS_GOOD); -} - -/* - * []---- - * | spc_pr_register_and_move - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static int -spc_pr_register_and_move(t10_cmd_t *cmd, void *data, size_t data_len) -{ - return (STATUS_RESERVATION_CONFLICT); -} - -/* - * []---- - * | spc_pr_key_alloc - - * | Allocate a new registration key and add it to the key list. - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static spc_pr_key_t * -spc_pr_key_alloc(scsi3_pgr_t *pgr, uint64_t service_key, uint64_t isid, - char *transportID) -{ - spc_pr_key_t *key = (spc_pr_key_t *) - memalign(sizeof (void *), sizeof (spc_pr_key_t)); - - if (key != NULL) { - key->k_key = service_key; - key->k_isid = isid; - key->k_transportID = strdup(transportID); - - insque(&key->k_link, pgr->pgr_keylist.lnk_bwd); - - pgr->pgr_numkeys++; - assert(pgr->pgr_numkeys > 0); - } - - return (key); -} - -/* - * []---- - * | spc_pr_key_rsrv_init - - * | Initialize registration & reservervation queues - * []---- - */ -static void -spc_pr_key_rsrv_init(scsi3_pgr_t *pgr) -{ - assert(pgr->pgr_numrsrv == 0); - assert(pgr->pgr_numkeys == 0); - pgr->pgr_rsrvlist.lnk_fwd = (key_link_t *)&pgr->pgr_rsrvlist.lnk_fwd; - - assert(pgr->pgr_rsrvlist.lnk_bwd == NULL); - pgr->pgr_rsrvlist.lnk_bwd = (key_link_t *)&pgr->pgr_rsrvlist.lnk_fwd; - - assert(pgr->pgr_keylist.lnk_fwd == NULL); - pgr->pgr_keylist.lnk_fwd = (key_link_t *)&pgr->pgr_keylist.lnk_fwd; - - assert(pgr->pgr_keylist.lnk_bwd == NULL); - pgr->pgr_keylist.lnk_bwd = (key_link_t *)&pgr->pgr_keylist.lnk_fwd; -} - -/* - * []---- - * | spc_pr_key_free - - * | Free a registration key - * []---- - */ -static void -spc_pr_key_free(scsi3_pgr_t *pgr, spc_pr_key_t *key) -{ - remque(&key->k_link); - free(key->k_transportID); - free(key); - - pgr->pgr_numkeys--; - assert(pgr->pgr_numkeys >= 0); -} - -/* - * []---- - * | spc_pr_key_find - - * | Find a registration key based on the key, owner id and port id. - * []---- - */ -static spc_pr_key_t * -spc_pr_key_find(scsi3_pgr_t *pgr, uint64_t key, uint64_t isid, - char *transportID) -{ - spc_pr_key_t *kp; - spc_pr_key_t *rval = NULL; - - - for (kp = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - kp != (spc_pr_key_t *)&pgr->pgr_keylist; - kp = (spc_pr_key_t *)kp->k_link.lnk_fwd) { - if ((key == 0 || kp->k_key == key) && - (isid == 0 || kp->k_isid == isid) && - (strlen(transportID) == 0 || - (strcmp(kp->k_transportID, transportID) == 0))) { - rval = kp; - break; - } - } - - return (rval); -} - - -/* - * []---- - * | spc_pr_rsrv_alloc - - * | Allocate a new reservation and add it to the rsrv list. - * []---- - */ -static spc_pr_rsrv_t * -spc_pr_rsrv_alloc(scsi3_pgr_t *pgr, uint64_t service_key, uint64_t isid, - char *transportID, uint8_t scope, uint8_t type) -{ - spc_pr_rsrv_t *rsrv = (spc_pr_rsrv_t *) - memalign(sizeof (void *), sizeof (spc_pr_rsrv_t)); - - if (rsrv != NULL) { - rsrv->r_key = service_key; - rsrv->r_isid = isid; - rsrv->r_transportID = strdup(transportID); - rsrv->r_scope = scope; - rsrv->r_type = type; - - insque(&rsrv->r_link, pgr->pgr_rsrvlist.lnk_bwd); - - pgr->pgr_numrsrv++; - assert(pgr->pgr_numrsrv > 0); - } - - return (rsrv); -} - - -/* - * []---- - * | spc_pr_rsrv_free - - * | Free a reservation. - * []---- - */ -static void -spc_pr_rsrv_free(scsi3_pgr_t *pgr, spc_pr_rsrv_t *rsrv) -{ - remque(&rsrv->r_link); - free(rsrv->r_transportID); - free(rsrv); - - pgr->pgr_numrsrv--; - assert(pgr->pgr_numrsrv >= 0); -} - -/* - * []---- - * | spc_pr_rsrv_find - - * | Find a reservation based on the key, owner id and port id. - * []---- - */ -static spc_pr_rsrv_t * -spc_pr_rsrv_find(scsi3_pgr_t *pgr, uint64_t key, uint64_t isid, - char *transportID) -{ - spc_pr_rsrv_t *rp, *rval = NULL; - - for (rp = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; - rp != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; - rp = (spc_pr_rsrv_t *)rp->r_link.lnk_fwd) { - if ((key == 0 || rp->r_key == key) && - (isid == 0 || rp->r_isid == isid) && - (strlen(transportID) == 0 || - (strcmp(rp->r_transportID, transportID) == 0))) { - rval = rp; - break; - } - } - - return (rval); -} - -/* - * []---- - * | spc_pr_erase - - * | Find specified key / reservation and erease it - * []---- - */ -/* - */ -static void -spc_pr_erase(scsi3_pgr_t *pgr) -{ - spc_pr_key_t *key; - spc_pr_rsrv_t *rsrv; - - while ((key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd) != - (spc_pr_key_t *)&pgr->pgr_keylist) { - spc_pr_key_free(pgr, key); - } - - assert(pgr->pgr_numkeys == 0); - - while ((rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd) != - (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist) { - spc_pr_rsrv_free(pgr, rsrv); - } - - assert(pgr->pgr_numrsrv == 0); - - pgr->pgr_generation = 0; - pgr->pgr_aptpl = 0; -} - -/* - * []---- - * | spc_pr_rsrv_release - - * | Release the reservation the perform any other required clearing actions. - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static void -spc_pr_rsrv_release(t10_cmd_t *cmd, scsi3_pgr_t *pgr, spc_pr_rsrv_t *rsrv) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - t10_lu_impl_t *lu; - spc_pr_key_t *key; - - /* - * For Registrants-Only mode set UNIT ATTN. - */ - if (rsrv->r_type == PGR_TYPE_WR_EX_RO || - rsrv->r_type == PGR_TYPE_EX_AC_RO) { - - for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - key != (spc_pr_key_t *)&pgr->pgr_keylist; - key = (spc_pr_key_t *)key->k_link.lnk_fwd) { - - /* - * No UNIT ATTN for the requesting Initiator. - */ - if (key->k_isid == T10_PGR_ISID(cmd)) - continue; - - /* - * Find associated I_T Nexuses - */ - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_cmd = sbc_cmd; - lu->l_status = KEY_UNIT_ATTENTION; - lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; - lu->l_ascq = SPC_ASCQ_RES_RELEASED; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, - lu); - } while (lu != NULL); - } - } - - /* - * Remove the reservation. - */ - spc_pr_rsrv_free(pgr, rsrv); -} - -/* - * []---- - * | spc_pr_read - - * | Read in pgr keys and reservations for this device from backend storage. - * | At least the local pgr write lock must be held. - * []---- - */ -Boolean_t -spc_pr_read(t10_cmd_t *cmd) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_key_t *key; - spc_pr_rsrv_t *rsrv; - spc_pr_diskkey_t *klist; - spc_pr_diskrsrv_t *rlist; - spc_pr_persist_disk_t *buf = NULL; - t10_lu_impl_t *lu; - int i, pfd; - Boolean_t status = False; - char path[MAXPATHLEN]; - - /* - * If the pre-processor supported "#if .. sizeof", these would - * not be required here - */ - assert(sizeof (spc_pr_diskkey_t) == 256); - assert(sizeof (spc_pr_diskrsrv_t) == 256); - assert(sizeof (spc_pr_persist_disk_t) == 512); - - /* - * Open/create the PERSISTANCE file specification - */ - (void) snprintf(path, MAXPATHLEN, "%s/%s/%s%d", - target_basedir, cmd->c_lu->l_targ->s_targ_base, - PERSISTANCEBASE, cmd->c_lu->l_common->l_num); - if ((pfd = open(path, O_RDONLY)) >= 0) { - struct stat pstat; - if ((fstat(pfd, &pstat)) == 0) - if (pstat.st_size > 0) - if (buf = malloc(pstat.st_size)) - if (read(pfd, buf, pstat.st_size) == - pstat.st_size) - status = True; - } - - /* - * Clean up on no persistence file found - */ - if (status == False) { - if (pfd >= 0) - close(pfd); - if (buf) - free(buf); - return (status); - } - - /* - * If this is the first time using the persistance data, - * initialize the reservation and resource key queues - */ - if (pgr->pgr_rsrvlist.lnk_fwd == NULL) { - spc_pr_key_rsrv_init(pgr); - } - - /* - * Perform some vailidation - */ - if ((buf->magic != PGRMAGIC) || - (buf->revision != SPC_PGR_PERSIST_DATA_REVISION)) { - status = False; - goto done; - } - - /* - * Get the registration keys. - */ - klist = buf->keylist; - for (i = 0; i < buf->numkeys; i++) { - if (klist[i].rectype != PGRDISKKEY) { - status = False; - goto done; - } - key = spc_pr_key_alloc(pgr, klist[i].key, klist[i].isid, - klist[i].transportID); - if (key == NULL) { - status = False; - goto done; - } - } - - /* - * Get the reservations. - */ - rlist = (spc_pr_diskrsrv_t *)&buf->keylist[buf->numkeys]; - for (i = 0; i < buf->numrsrv; i++) { - if (rlist[i].rectype != PGRDISKRSRV) { - status = False; - goto done; - } - rsrv = spc_pr_rsrv_alloc(pgr, rlist[i].key, rlist[i].isid, - rlist[i].transportID, rlist[i].scope, rlist[i].type); - if (rsrv == NULL) { - status = False; - goto done; - } - } - - /* - * If there was data then set the reservation type. - */ - if (pgr->pgr_numkeys > 0 || pgr->pgr_numrsrv > 0) { - res->res_type = RT_PGR; - pgr->pgr_generation = buf->generation; - - /* - * Set the command dispatcher according to the reservation type - */ - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_cmd = sbc_cmd_reserved; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - } - -done: pthread_rwlock_unlock(&res->res_rwlock); - free(buf); - return (status); -} - -/* - * []---- - * | spc_pr_write - - * | Write PGR keys and reservations for this device to backend storage. - * | At least the local pgr write lock must be held. - * []---- - */ -Boolean_t -spc_pr_write(t10_cmd_t *cmd) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_key_t *key; - spc_pr_rsrv_t *rsrv; - spc_pr_diskkey_t *klist; - spc_pr_diskrsrv_t *rlist; - spc_pr_persist_disk_t *buf; - ssize_t length, bufsize; - int i, pfd = -1; - char path[MAXPATHLEN]; - Boolean_t status = True; - - /* - * If the pre-processor supported "#if .. sizeof", these would - * not be required here - */ - assert(sizeof (spc_pr_diskkey_t) == 256); - assert(sizeof (spc_pr_diskrsrv_t) == 256); - assert(sizeof (spc_pr_persist_disk_t) == 512); - - /* - * 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. - */ - bufsize = sizeof (spc_pr_persist_disk_t) + - (pgr->pgr_numkeys - 1) * sizeof (spc_pr_diskkey_t) + - pgr->pgr_numrsrv * sizeof (spc_pr_diskrsrv_t); - bufsize = roundup(bufsize, 512); - if ((buf = memalign(sizeof (void *), bufsize)) == NULL) - return (False); - else - bzero(buf, bufsize); - - /* - * Build header. - */ - buf->magic = PGRMAGIC; - buf->revision = SPC_PGR_PERSIST_DATA_REVISION; - buf->generation = pgr->pgr_generation; - buf->numkeys = pgr->pgr_numkeys; - buf->numrsrv = pgr->pgr_numrsrv; - - /* - * Copy the keys. - */ - klist = buf->keylist; - for (i = 0, key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - key != (spc_pr_key_t *)&pgr->pgr_keylist && i < pgr->pgr_numkeys; - key = (spc_pr_key_t *)key->k_link.lnk_fwd, i++) { - - klist[i].rectype = PGRDISKKEY; - klist[i].reserved = 0; - klist[i].key = key->k_key; - klist[i].isid = key->k_isid; - strncpy(klist[i].transportID, key->k_transportID, - sizeof (klist[i].transportID)); - } - - /* - * Copy the reservations. - */ - rlist = (spc_pr_diskrsrv_t *)&buf->keylist[pgr->pgr_numkeys]; - for (i = 0, rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; - rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist && - i < pgr->pgr_numrsrv; - rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd, i++) { - - rlist[i].rectype = PGRDISKRSRV; - rlist[i].reserved = 0; - rlist[i].scope = rsrv->r_scope; - rlist[i].type = rsrv->r_type; - rlist[i].key = rsrv->r_key; - rlist[i].isid = rsrv->r_isid; - strncpy(rlist[i].transportID, rsrv->r_transportID, - sizeof (rlist[i].transportID)); - } - - /* - * Open/create the PERSISTANCE file specification - */ - (void) snprintf(path, MAXPATHLEN, "%s/%s/%s%d", - target_basedir, cmd->c_lu->l_targ->s_targ_base, - PERSISTANCEBASE, cmd->c_lu->l_common->l_num); - if ((pfd = open(path, O_WRONLY|O_CREAT)) >= 0) { - length = write(pfd, buf, bufsize); - close(pfd); - } else { - if ((pfd < 0) || (length != bufsize)) - status = False; - } - - /* - * Free allocated buffer - */ - free(buf); - return (status); -}
--- a/deleted_files/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h Thu Sep 13 13:50:11 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _T10_SPC_PR_H -#define _T10_SPC_PR_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * SPC-3 Persistent Reservation specific structures and defines - */ - -/* - * Key Linked Lists - */ -typedef struct key_link { - union { - uint64_t align; - struct { - struct key_link *_lnk_fwd; /* Forward element */ - struct key_link *_lnk_bwd; /* Backward element */ - } key_ptr; - } key_link; -} key_link_t; -#define lnk_fwd key_link.key_ptr._lnk_fwd -#define lnk_bwd key_link.key_ptr._lnk_bwd -#define insque(a, b) do { \ - ((key_link_t *)(a))->lnk_fwd = (key_link_t *)(b); \ - ((key_link_t *)(a))->lnk_bwd = ((key_link_t *)(b))->lnk_bwd; \ - ((key_link_t *)(b))->lnk_bwd = (key_link_t *)(a); \ - ((key_link_t *)(a))->lnk_bwd->lnk_fwd = (key_link_t *)(a); \ - } while (0) - -#define remque(A) do { \ - ((key_link_t *)(A))->lnk_bwd->lnk_fwd = ((key_link_t *)(A))->lnk_fwd; \ - ((key_link_t *)(A))->lnk_fwd->lnk_bwd = ((key_link_t *)(A))->lnk_bwd; \ - } while (0) - -/* - * Reservation Types (res_type). - */ -typedef enum { - RT_NONE = 0, /* None */ - RT_PGR /* SCSI-3 Persistent Reservation */ -} spc_reserve_types; - -/* - * Persistent reservation data. - */ -typedef struct spc_pr_key { - key_link_t k_link; /* Key linked list */ - uint64_t k_key; /* registration key */ - uint64_t k_isid; /* Owner ISID */ - char *k_transportID; /* transport ID */ -} spc_pr_key_t; - -typedef struct spc_pr_rsrv { - key_link_t r_link; /* Key linked list */ - uint64_t r_key; /* reservation key */ - uint64_t r_isid; /* Owner ISID */ - char *r_transportID; /* transport ID */ - uint8_t r_scope; /* reservation scope */ - uint8_t r_type; /* reservation type */ -} spc_pr_rsrv_t; - -/* - * Persistent Reservation data - */ -typedef struct scsi3_pgr { - uint32_t pgr_generation; /* PGR PRgeneration value */ - uint16_t pgr_unused; - uint16_t pgr_bits : 15, - pgr_aptpl : 1; /* persistence data exists */ - int32_t pgr_numkeys; /* # entries in key list */ - int32_t pgr_numrsrv; /* # entries in rsrv list */ - key_link_t pgr_keylist; /* Registration key list */ - key_link_t pgr_rsrvlist; /* reservation list */ -} scsi3_pgr_t; - -typedef struct sbc_reserve { - spc_reserve_types res_type; /* standard or pr active */ - pthread_rwlock_t res_rwlock; /* Lock for coordination */ - scsi3_pgr_t res_scsi_3_pgr; /* SCSI-3 PGR */ -} sbc_reserve_t; - -/* - * On-disk PGR data. - * - * NOTE: The following three structures should be rounded up to 256 bytes each - * to prevent potential problems with on-disk data. - */ -typedef struct spc_pr_diskkey { - uint32_t rectype; /* record type */ - uint32_t reserved; - uint64_t key; /* registration key */ - uint64_t isid; /* Owner ISID */ - char transportID[228]; /* transport ID */ - char filler[4]; /* Unsed, round to 256 bytes */ -} spc_pr_diskkey_t; - -typedef struct spc_pr_diskrsrv { - uint32_t rectype; /* record type */ - uint16_t reserved; - uint8_t scope; /* reservation scope */ - uint8_t type; /* reservation type */ - uint64_t key; /* reservation key */ - uint64_t isid; /* Owner ISID */ - char transportID[228]; /* Transport ID */ - char filler[4]; /* Unsed, round to 256 bytes */ -} spc_pr_diskrsrv_t; - -typedef struct spc_pr_persist_disk { - uint64_t magic; /* magic number */ - uint32_t revision; /* header format revision */ - uint32_t generation; /* pgr generation count */ - int32_t numkeys; /* # items in key list */ - int32_t numrsrv; /* # items in rsrv list */ - char filler[232]; /* Unused, round to 256 bytes */ - -/* - * After the header the data is laid out as follows: - * spc_pr_diskkey_t keylist[]; - * spc_pr_diskrsrv_t rsrvlist[]; - */ - spc_pr_diskkey_t keylist[1]; -} spc_pr_persist_disk_t; - - -#define SPC_PGR_PERSIST_DATA_REVISION 0x01 /* REVISON = 1 */ -#define PGRMAGIC 0x5047524D41474943LL /* "PGRMAGIC" */ -#define PGRDISKKEY 0x5047526B /* "PGRk" */ -#define PGRDISKRSRV 0x50475272 /* "PGRr" */ - -#ifdef __cplusplus -} -#endif - -#endif /* _T10_SPC_PR_H */
--- a/deleted_files/usr/src/uts/common/sys/scsi/generic/persist.h Thu Sep 13 13:50:11 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,398 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _SYS_SCSI_GENERIC_PERSIST_H -#define _SYS_SCSI_GENERIC_PERSIST_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * SCSI Persistence Data - * - * Format of data returned as a result of PERSISTENCE RESERVER { IN | OUT } - */ - -/* - * SPC-3 revision 23, Section 6.11.1, Table 102 - * Persistent Reservations - * Persistent Reserve In service actions - */ -#define PR_IN_READ_KEYS 0x0 /* Read all registered reservation keys */ -#define PR_IN_READ_RESERVATION 0x1 /* Reads th persistent reservations */ -#define PR_IN_REPORT_CAPABILITIES 0x2 /* Returns capability information */ -#define PR_IN_READ_FULL_STATUS 0x3 /* Reads complete information about all */ - /* registrations and the persistent */ - /* reservations, if any */ -/* - * SPC-3 revision 23, Section 6.11.3.3, Table 106 - * Persistent reservation scope codes - */ -#define PR_LU_SCOPE 0x0 /* Persistent reservation applies to */ - /* full logical unit */ -/* - * SPC-3 revision 23, Section 6.11.3.4, Table 107 - * Persistent Reservations - * Persistent reservation type codes - */ -#define PGR_TYPE_WR_EX 0x1 /* Write Exclusive */ -#define PGR_TYPE_EX_AC 0x3 /* Exclusive Access */ -#define PGR_TYPE_WR_EX_RO 0x5 /* Write Exclusive, Registrants Only */ -#define PGR_TYPE_EX_AC_RO 0x6 /* Exclusive Access, Registrants Only */ -#define PGR_TYPE_WR_EX_AR 0x7 /* Write Exclusive, All Registrants */ -#define PGR_TYPE_EX_AC_AR 0x8 /* Exclusive Access, All Registrants */ - -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11.5 PERSISTENCE RESERVE IN - * Table 111 - full status descriptor format - */ -/* Table 289 - iSCSI Initiator Device TransportID format */ - -#define iSCSI_PROTOCOL_ID 0x5 /* Table 262 - iSCSI Protocol ID */ -#define WW_UID_DEVICE_NAME 0x0 /* Table 288 - iSCSI Transport IDs */ - - -#if defined(_BIT_FIELDS_LTOH) -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11.1 PERSISTENCE RESERVE IN - * Table 101 - PERSISTENCE RESERVE IN command - */ -typedef struct scsi_cdb_prin { - uint8_t cmd; - uint8_t action : 5, - resbits : 3; - uint8_t resbytes[5]; - uint8_t alloc_len[2]; - uint8_t control; -} scsi_cdb_prin_t; - -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11.2 PERSISTENCE RESERVE IN - * Table 103/104/105 - parameter data for READS KEYS - */ -typedef struct scsi_prin_rsrvdesc { - uint8_t reservation_key[8]; - uint8_t obsolete1[4]; - uint8_t resbytes; - uint8_t type : 4, - scope : 4; - uint8_t obsolete2[2]; -} scsi_prin_rsrvdesc_t; -typedef struct scsi_prin_readrsrv { - uint8_t PRgeneration[4]; - uint8_t add_len[4]; - scsi_prin_rsrvdesc_t res_key_list[1]; -} scsi_prin_readrsrv_t; - -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11.4 PERSISTENCE RESERVE IN - * Table 108 - parameter data for REPORT CAPABILTIES - */ -typedef struct scsi_per_res_type { - uint8_t resbits1 : 1, - wr_ex : 1, - resbits2 : 1, - ex_ac : 1, - resbits3 : 1, - wr_ex_ro : 1, - ex_ac_ro : 1, - wr_ex_ar : 1; - uint8_t ex_ac_ar : 1, - resbits4 : 7; -} scsi_per_res_type_t; -typedef struct scsi_prin_rpt_cap { - uint8_t length[2]; - uint8_t ptpl_c : 1, - resbits1 : 1, - atp_c : 1, - sip_c : 1, - crh : 1, - resbits2 : 3; - uint8_t ptpl_a : 1, - resbits3 : 6, - tmv : 1; - scsi_per_res_type_t pr_type; - uint8_t resbytes[2]; -} scsi_prin_rpt_cap_t; - -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11.5 PERSISTENCE RESERVE IN - * Table 110/111 - parameter data for READ FULL STATUS - * Table 281 - TransportId format - */ -typedef struct scsi_transport_id { - uint8_t protocol_id : 4, - resbits : 2, - format_code : 2; - uint8_t add_len[2]; - char iscsi_name[1]; -} scsi_transport_id_t; -typedef struct scsi_prin_status_t { - uint8_t reservation_key[8]; - uint8_t resbytes1[4]; - uint8_t r_holder : 1, - all_tg_pt : 1, - resbits : 6; - uint8_t type : 4, - scope : 4; - uint8_t resbytes2[4]; - uint8_t rel_tgt_port_id[2]; - uint8_t add_len[4]; - scsi_transport_id_t trans_id; -} scsi_prin_status_t; -typedef struct scsi_prin_full_status { - uint8_t PRgeneration[4]; - uint8_t add_len[4]; - scsi_prin_status_t full_desc[1]; -} scsi_prin_full_status_t; - -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.12.1 PERSISTENCE RESERVE OUT - * Table 112 - PERSISTENCE RESERVE OUT command - */ -typedef struct scsi_cdb_prout { - uint8_t cmd; - uint8_t action : 5, - resbits : 3; - uint8_t type : 4, - scope : 4; - uint8_t resbytes[2]; - uint8_t param_len[4]; - uint8_t control; -} scsi_cdb_prout_t; - -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.12.3 PERSISTENCE RESERVE OUT - * Table 114 - PERSISTENCE RESERVE OUT parameter list - */ -typedef struct scsi_prout_plist { - uint8_t reservation_key[8]; - uint8_t service_key[8]; - uint8_t obsolete1[4]; - uint8_t aptpl : 1, - resbits1 : 1, - all_tg_pt : 1, - spec_i_pt : 1, - resbits2 : 4; - uint8_t resbytes1; - uint8_t obsolete2[2]; - uint8_t apd[1]; -} scsi_prout_plist_t; - -#elif defined(_BIT_FIELDS_HTOL) -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11.1 PERSISTENCE RESERVE IN - * Table 101 - PERSISTENCE RESERVE IN command - */ -typedef struct scsi_cdb_prin { - uint8_t cmd; - uint8_t resbits : 3, - action : 5; - uint8_t resbytes[5]; - uint8_t alloc_len[2]; - uint8_t control; -} scsi_cdb_prin_t; - -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11.2 PERSISTENCE RESERVE IN - * Table 103/104/105 - parameter data for READS KEYS - */ -typedef struct scsi_prin_rsrvdesc { - uint8_t reservation_key[8]; - uint8_t obsolete1[4]; - uint8_t resbytes; - uint8_t scope : 4, - type : 4; - uint8_t obsolete2[8]; -} scsi_prin_rsrvdesc_t; -typedef struct scsi_prin_readrsrv { - uint8_t PRgeneration[4]; - uint8_t add_len[4]; - scsi_prin_rsrvdesc_t res_key_list[1]; -} scsi_prin_readrsrv_t; - -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11.4 PERSISTENCE RESERVE IN - * Table 108 - parameter data for REPORT CAPABILTIES - */ -typedef struct scsi_per_res_type { - uint8_t wr_ex_ar : 1, - ex_ac_ro : 1, - wr_ex_ro : 1, - resbits3 : 1, - ex_ac : 1, - resbits2 : 1, - wr_ex : 1, - resbits1 : 1; - uint8_t resbits4 : 7, - ex_ac_ar : 1; -} scsi_per_res_type_t; -typedef struct scsi_prin_rpt_cap { - uint8_t length[2]; - uint8_t resbits2 : 3, - crh : 1, - sip_c : 1, - atp_c : 1, - resbits1 : 1, - ptpl_c : 1; - uint8_t tmv : 1, - resbits3 : 6, - ptpl_a : 1; - scsi_per_res_type_t pr_type; - uint8_t resbytes[2]; -} scsi_prin_rpt_cap_t; - -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11.5 PERSISTENCE RESERVE IN - * Table 110/111 - parameter data for READ FULL STATUS - * Table 281 - TransportId format - */ -typedef struct scsi_transport_id { - uint8_t format_code : 2, - resbits : 2, - protocol_id : 4; - uint8_t add_len[2]; - char iscsi_name[1]; -} scsi_transport_id_t; -typedef struct scsi_prin_status_t { - uint8_t reservation_key[8]; - uint8_t resbytes1[4]; - uint8_t resbits : 6, - all_tg_pt : 1, - r_holder : 1; - uint8_t scope : 4, - type : 4; - uint8_t resbytes2[4]; - uint8_t rel_tgt_port_id[2]; - uint8_t add_len[4]; - scsi_transport_id_t trans_id; -} scsi_prin_status_t; -typedef struct scsi_prin_full_status { - uint8_t PRgeneration[4]; - uint8_t add_len[4]; - scsi_prin_status_t full_desc[1]; -} scsi_prin_full_status_t; - -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.12.1 PERSISTENCE RESERVE OUT - * Table 112 - PERSISTENCE RESERVE OUT command - */ -typedef struct scsi_cdb_prout { - uint8_t cmd; - uint8_t resbits : 3, - action : 5; - uint8_t scope : 4, - type : 4; - uint8_t resbytes[2]; - uint8_t param_len[4]; - uint8_t control; -} scsi_cdb_prout_t; - -/* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.12.3 PERSISTENCE RESERVE OUT - * Table 114 - PERSISTENCE RESERVE OUT parameter list - */ -typedef struct scsi_prout_plist { - uint8_t reservation_key[8]; - uint8_t service_key[8]; - uint8_t obsolete1[4]; - uint8_t resbits1 : 4, - spec_i_pt : 1, - all_tg_pt : 1, - resbits2 : 1, - aptpl : 1; - uint8_t resbytes1; - uint8_t obsolete2[2]; - uint8_t apd[1]; -} scsi_prout_plist_t; - -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif /* _BIT_FIELDS_LTOH */ - - -/* - * SPC-3 revision 23, Section 6.12.2, Table 113 - * Persistent Reservations - * Persistent Reserve Out service action codes - */ -#define PR_OUT_REGISTER 0x0 /* Register/unregister a reservation */ - /* key with the device server */ -#define PR_OUT_RESERVE 0x1 /* Create a persistent reservation */ - /* having a specified SCOPE & TYPE */ -#define PR_OUT_RELEASE 0x2 /* Release the selected persistent */ - /* reservation */ -#define PR_OUT_CLEAR 0x3 /* Clears all reservation keys and */ - /* all persistent reservations */ -#define PR_OUT_PREEMPT 0x4 /* Preempts persistent reservations */ - /* and/or removes reservations */ -#define PR_OUT_PREEMPT_ABORT 0x5 /* Preempts persistent reservations */ - /* and/or removes reservations, and */ - /* aborts all tasks for all preempted */ - /* I_T nexuses */ -#define PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY 0x06 - /* Register a reservation key with */ - /* the device server, or unregister a */ - /* reservation key */ -#define PR_OUT_REGISTER_MOVE 0x7 /* Register a reservation key for */ - /* another I_T nexus with the device */ - /* server and move a persistent */ - /* reservation to the I_T nexus */ - - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_SCSI_GENERIC_PERSIST_H */
--- a/usr/src/cmd/iscsi/iscsitgtd/Makefile Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/Makefile Thu Sep 13 15:17:59 2007 -0700 @@ -31,7 +31,7 @@ OBJS += iscsi_authclient.o iscsi_authglue.o iscsi_cmd.o iscsi_conn.o OBJS += iscsi_crc.o iscsi_ffp.o iscsi_login.o iscsi_sess.o radius.o OBJS += t10_sam.o t10_spc.o t10_sbc.o t10_raw_if.o t10_ssc.o t10_osd.o -OBJS += util.o util_err.o util_ifname.o util_port.o util_queue.o +OBJS += t10_spc_pr.o util.o util_err.o util_ifname.o util_port.o util_queue.o OBJS += isns_client.o isns.o POFILE= iscsitgtd.po POFILES = $(OBJS:%.o=%.po)
--- a/usr/src/cmd/iscsi/iscsitgtd/Makefile.com Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/Makefile.com Thu Sep 13 15:17:59 2007 -0700 @@ -34,7 +34,7 @@ COBJS += iscsi_authclient.o iscsi_authglue.o iscsi_cmd.o iscsi_conn.o COBJS += iscsi_crc.o iscsi_ffp.o iscsi_login.o iscsi_sess.o radius.o COBJS += t10_sam.o t10_spc.o t10_sbc.o t10_raw_if.o t10_ssc.o t10_osd.o -COBJS += util.o util_err.o util_ifname.o util_port.o util_queue.o +COBJS += t10_spc_pr.o util.o util_err.o util_ifname.o util_port.o util_queue.o COBJS += isns_client.o isns.o OBJS= $(COBJS) $(DSRC:%.d=%.o) SRCS= $(COBJS:%.o=../%.c) $(COMMON_SRCS)
--- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.c Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.c Thu Sep 13 15:17:59 2007 -0700 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -71,8 +71,7 @@ Boolean_t session_alloc(iscsi_conn_t *c, uint8_t *isid) { - iscsi_sess_t *s, - *n; + iscsi_sess_t *s, *n; if (c->c_sess != NULL) return (True); @@ -187,8 +186,7 @@ convert_i_local(char *ip, char **rtn) { tgt_node_t *inode = NULL; - char *iname, - *name; + char *iname, *name; while ((inode = tgt_node_next(main_config, XML_ELEMENT_INIT, inode)) != NULL) { @@ -298,8 +296,7 @@ mgmt_request_t *mgmt; name_request_t *nr; t10_cmd_t *t10_cmd; - char **buf, - local_buf[16]; + char **buf, local_buf[16]; int lun; extern void dataout_callback(t10_cmd_t *t, char *data, size_t *xfer); @@ -321,8 +318,9 @@ * XXX Need to rethink how I should do * the callback. */ - s->s_t10 = t10_handle_create(s->s_t_name, - T10_TRANS_ISCSI, s->s_conn_head->c_tpgt, + s->s_t10 = t10_handle_create( + s->s_t_name, s->s_i_name, T10_TRANS_ISCSI, + s->s_conn_head->c_tpgt, s->s_conn_head->c_max_burst_len, s->s_t10q, dataout_callback); } @@ -681,7 +679,7 @@ } if (iscsiAuthClientSetVersion(auth_client, - iscsiAuthVersionRfc) != iscsiAuthStatusNoError) { + iscsiAuthVersionRfc) != iscsiAuthStatusNoError) { syslog(LOG_ERR, "iscsi connection login failed - " "unable to set version\n"); return; @@ -716,8 +714,7 @@ } if (iscsiAuthClientSetAuthRemote(auth_client, - isp->sess_auth.auth_enabled) != - iscsiAuthStatusNoError) { + isp->sess_auth.auth_enabled) != iscsiAuthStatusNoError) { syslog(LOG_ERR, "iscsi connection login failed - " "unable to set remote authentication\n"); return;
--- a/usr/src/cmd/iscsi/iscsitgtd/main.c Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/main.c Thu Sep 13 15:17:59 2007 -0700 @@ -89,7 +89,8 @@ Boolean_t enforce_strict_guid = True, thin_provisioning = False, disable_tpgs = False, - dbg_timestamps = False; + dbg_timestamps = False, + pgr_persist = True; int targets_vers_maj, targets_vers_min, main_vers_maj, @@ -370,6 +371,8 @@ &disable_tpgs); (void) tgt_find_value_boolean(node, XML_ELEMENT_TIMESTAMPS, &dbg_timestamps); + (void) tgt_find_value_boolean(node, XML_ELEMENT_PGR_PERSIST, + &pgr_persist); if (tgt_find_value_int(node, XML_ELEMENT_LOGLVL, &qlog_lvl) == True) queue_log(True);
--- a/usr/src/cmd/iscsi/iscsitgtd/queue.h Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/queue.h Thu Sep 13 15:17:59 2007 -0700 @@ -41,29 +41,39 @@ #include <iscsitgt_impl.h> -#define Q_CONN_ERRS 0x00001 -#define Q_CONN_LOGIN 0x00002 -#define Q_CONN_NONIO 0x00004 -#define Q_CONN_IO 0x00008 +/* Connections */ +#define Q_CONN_ERRS 0x00000001 +#define Q_CONN_LOGIN 0x00000002 +#define Q_CONN_NONIO 0x00000004 +#define Q_CONN_IO 0x00000008 + +/* Sessions */ +#define Q_SESS_ERRS 0x00000010 +#define Q_SESS_LOGIN 0x00000020 +#define Q_SESS_NONIO 0x00000040 +#define Q_SESS_IO 0x00000080 -#define Q_SESS_ERRS 0x00010 -#define Q_SESS_LOGIN 0x00020 -#define Q_SESS_NONIO 0x00040 -#define Q_SESS_IO 0x00080 +/* SCSI Target Emulation */ +#define Q_STE_ERRS 0x00000100 +#define Q_STE_NONIO 0x00000200 +#define Q_STE_IO 0x00000400 -#define Q_STE_ERRS 0x00100 -#define Q_STE_NONIO 0x00200 -#define Q_STE_IO 0x00400 +/* General Errors */ +#define Q_GEN_ERRS 0x00001000 +#define Q_GEN_DETAILS 0x00002000 -#define Q_GEN_ERRS 0x01000 -#define Q_GEN_DETAILS 0x02000 +/* ISCSI Debugging */ +#define Q_ISNS_DBG 0x00004000 -#define Q_ISNS_DBG 0x10000 +/* Persistent Reservations */ +#define Q_PR_ERRS 0x00010000 +#define Q_PR_NONIO 0x00020000 +#define Q_PR_IO 0x00040000 /* * When used the queue request will be place at the head of the queue. */ -#define Q_HIGH 0x10000 +#define Q_HIGH 0x80000000 extern int qlog_lvl;
--- a/usr/src/cmd/iscsi/iscsitgtd/t10.h Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/t10.h Thu Sep 13 15:17:59 2007 -0700 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -126,6 +126,8 @@ #define T10_CMD_RESID(cmd) (cmd->c_resid) #define T10_SENSE_LEN(cmd) (cmd->c_cmd_sense_len) #define T10_SENSE_DATA(cmd) (cmd->c_cmd_sense) +#define T10_PGR_TNAME(cmd) (cmd->c_lu->l_targ->s_targ_base) +#define T10_PGR_INAME(cmd) (cmd->c_lu->l_targ->s_i_name) #define T10_DEFAULT_TPG 1 @@ -341,7 +343,7 @@ Boolean_t l_fast_write_ack; /* - * AVL tree containing all I_T_Q nexus' which are actively using + * AVL tree containing all I_T_L nexus' which are actively using * this LUN. */ avl_tree_t l_all_open; @@ -366,7 +368,7 @@ } t10_lu_common_t; /* - * Each I_T_Q has a LU structure associated with it. + * Each I_T_L has a LU structure associated with it. */ typedef struct t10_lu_impl { /* @@ -427,6 +429,7 @@ int l_targ_lun; Boolean_t l_dsense_enabled; + Boolean_t l_pgr_read; /* * Statistics on a per ITL basis @@ -449,6 +452,7 @@ } t10_lu_impl_t; typedef struct t10_targ_impl { + char *s_i_name; char *s_targ_base; int s_targ_num; /* used in log messages */ avl_tree_t s_open_lu; @@ -463,7 +467,7 @@ /* * Target Port Set */ - int s_tp_grp; + int s_tpgt; /* * transport version number to use in standard inquiry data @@ -528,8 +532,8 @@ * t10_handle_create -- create target handle to be used by transports */ t10_targ_handle_t -t10_handle_create(char *targ_name, int trans_version, int tpg, int max_out, - target_queue_t *transq, void (*datain_cb)(t10_cmd_t *, char *, size_t *)); +t10_handle_create(char *targ, char *init, int trans_vers, int tpg, int max_out, + target_queue_t *tq, void (*datain_cb)(t10_cmd_t *, char *, size_t *)); /* * t10_handle_disable -- drains commands from emulation queues
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_raw_if.c Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/t10_raw_if.c Thu Sep 13 15:17:59 2007 -0700 @@ -234,8 +234,8 @@ static void raw_read_tape(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) { - size_t req_len, - xfer; + size_t req_len; + size_t xfer; off_t offset = 0; raw_io_t *io; Boolean_t last; @@ -285,8 +285,8 @@ union scsi_cdb *u = (union scsi_cdb *)cdb; diskaddr_t addr; off_t offset = 0; - uint32_t cnt, - min; + uint32_t cnt; + uint32_t min; raw_io_t *io; uint64_t err_blkno; int sense_len; @@ -499,8 +499,8 @@ static void raw_write_tape(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) { - size_t request_len, - xfer; + size_t request_len; + size_t xfer; raw_io_t *io; request_len = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4]; @@ -824,6 +824,37 @@ } static void +raw_persist_in(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) +{ + raw_io_t *io; + + if ((io = do_datain(cmd, cdb, CDB_GROUP1, 0)) == NULL) { + trans_send_complete(cmd, STATUS_CHECK); + } else { + trans_send_complete(cmd, io->r_status); + raw_free_io(io); + } +} + +static void +raw_persist_out(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) +{ + size_t len; + + len = (cdb[5] << 24) | (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + do_dataout(cmd, cdb, cdb_len, len); +} + +/*ARGSUSED*/ +static void +raw_persist_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, + size_t data_len) +{ + raw_io_t *io = (raw_io_t *)id; + trans_send_complete(cmd, do_uscsi(cmd, io, RawDataToDevice)); +} + +static void raw_msense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) { raw_io_t *io; @@ -1351,8 +1382,8 @@ { spc_unsupported, NULL, NULL, NULL }, { spc_unsupported, NULL, NULL, NULL }, { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, + { raw_persist_in, NULL, NULL, "PERSISTENT_RESERVE_IN" }, + { raw_persist_out, raw_persist_data, NULL, "PERSISTENT_RESERVE_OUT" }, /* 0x60 -- 0x6f */ { spc_unsupported, NULL, NULL, NULL },
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_sam.c Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/t10_sam.c Thu Sep 13 15:17:59 2007 -0700 @@ -99,7 +99,7 @@ static sam_device_table_t sam_emul_table[]; /* - * Global variables + * Local variables */ static avl_tree_t lu_list; static pthread_mutex_t lu_list_mutex; @@ -205,7 +205,7 @@ * []---- */ t10_targ_handle_t -t10_handle_create(char *targ, int trans_version, int tpg, int max_out, +t10_handle_create(char *targ, char *init, int trans_vers, int tpg, int max_out, target_queue_t *tq, void (*datain_cb)(t10_cmd_t *, char *, size_t *)) { t10_targ_impl_t *t = calloc(1, sizeof (t10_targ_impl_t)); @@ -217,7 +217,8 @@ t->s_targ_num = t10_num++; (void) pthread_mutex_unlock(&t10_mutex); t->s_targ_base = strdup(targ); - t->s_trans_vers = trans_version; + t->s_i_name = strdup(init); + t->s_trans_vers = trans_vers; t->s_maxout = max_out; t->s_to_transport = tq; t->s_dataout_cb = datain_cb; @@ -234,13 +235,13 @@ * to determine relative path numbering there's no issue with changing * this later if need be. */ - switch (trans_version) { + switch (trans_vers) { case T10_TRANS_ISCSI: - t->s_tp_grp = 0x0000 | tpg; + t->s_tpgt = 0x0000 | tpg; break; case T10_TRANS_FC: - t->s_tp_grp = 0x8000 | tpg; + t->s_tpgt = 0x8000 | tpg; break; } @@ -286,8 +287,8 @@ { t10_targ_impl_t *t = (t10_targ_impl_t *)tp; t10_lu_impl_t *l; - t10_cmd_t *c, - *c2free; + t10_cmd_t *c; + t10_cmd_t *c2free; int fast_free = 0; (void) pthread_mutex_lock(&t->s_mutex); @@ -348,6 +349,7 @@ (void) pthread_mutex_unlock(&t->s_mutex); free(t->s_targ_base); + free(t->s_i_name); free(t); } @@ -689,8 +691,8 @@ t10_task_mgmt(t10_targ_handle_t t1, TaskOp_t op, int opt_lun, void *tag) { t10_targ_impl_t *t = (t10_targ_impl_t *)t1; - t10_lu_impl_t search, - *lu; + t10_lu_impl_t search; + t10_lu_impl_t *lu; switch (op) { case InventoryChange: @@ -753,8 +755,8 @@ { t10_targ_impl_t *t = (t10_targ_impl_t *)t1; t10_lu_impl_t *itl; - char lb[32], - *p; + char lb[32]; + char *p; /* * It's possible for the management interfaces to request stats @@ -819,8 +821,8 @@ t10_cmd_t *cmd = NULL; uint8_t cdb[16]; /* ---- fake buffer ---- */ diskaddr_t offset = 0; - size_t size, - sync_size; + size_t size; + size_t sync_size; msg_t *m = NULL; target_queue_t *rq = NULL; char path[MAXPATHLEN]; @@ -835,7 +837,7 @@ * having something fixed/change in one location that isn't * in another. Obvious right? */ - if ((t = t10_handle_create(target, 0, 0, 0, q, NULL)) == NULL) { + if ((t = t10_handle_create(target, "", 0, 0, 0, q, NULL)) == NULL) { queue_prt(mgmtq, Q_STE_ERRS, "STE%x Failed to create handle\n", lun); return (False); @@ -1311,19 +1313,19 @@ static Boolean_t t10_find_lun(t10_targ_impl_t *t, int lun, t10_cmd_t *cmd) { - t10_lu_impl_t *l = NULL, - search; - avl_index_t wc = 0, /* where common */ - wt = 0; /* where target */ - char *guid = NULL, - *str, - *dataset = NULL; - t10_lu_common_t lc, - *common = NULL; - tgt_node_t *n = NULL, - *n1, - *targ, - *ll; + t10_lu_impl_t *l = NULL; + t10_lu_impl_t search; + avl_index_t wc = 0; /* where common */ + avl_index_t wt = 0; /* where target */ + char *guid = NULL; + char *str; + char *dataset = NULL; + t10_lu_common_t lc; + t10_lu_common_t *common = NULL; + tgt_node_t *n = NULL; + tgt_node_t *n1; + tgt_node_t *targ; + tgt_node_t *ll; xmlTextReaderPtr r = NULL; char path[MAXPATHLEN]; int xml_fd = -1; @@ -1702,11 +1704,11 @@ msg_t *m; t10_lu_impl_t *itl; t10_cmd_t *cmd; - char *data, - *path; - size_t data_len, - new_size, - offset; + char *data; + char *path; + size_t data_len; + size_t new_size; + size_t offset; ssize_t cc; void *provo_err; t10_shutdown_t *s; @@ -1736,8 +1738,8 @@ trans_send_complete(cmd, STATUS_CHECK); } else { lu->l_curr = cmd; - (*cmd->c_lu->l_cmd)(cmd, cmd->c_cdb, - cmd->c_cdb_len); + (*cmd->c_lu->l_cmd) + (cmd, cmd->c_cdb, cmd->c_cdb_len); lu->l_curr = NULL; } break; @@ -1896,13 +1898,13 @@ cmd->c_data, cmd->c_data_len); cmd->c_lu->l_cmds_read++; cmd->c_lu->l_sects_read += - cmd->c_data_len / 512; + cmd->c_data_len / 512; bcopy(cmd->c_data, (char *)lu->l_mmap + cmd->c_offset, cmd->c_data_len); cmd->c_lu->l_cmds_write++; cmd->c_lu->l_sects_write += - cmd->c_data_len / 512; + cmd->c_data_len / 512; lu->l_curr = NULL; lu->l_curr_provo = False; provo_err = 0; @@ -1920,7 +1922,7 @@ lu->l_num, errno); } provo_err = (cc == cmd->c_data_len) ? - (void *)0 : (void *)1; + (void *)0 : (void *)1; } /* * acknowledge this op and wait for next @@ -2119,13 +2121,13 @@ static Boolean_t load_params(t10_lu_common_t *lu, char *basedir) { - char file[MAXPATHLEN], - *str; + char file[MAXPATHLEN]; + char *str; int oflags = O_RDWR|O_LARGEFILE|O_NDELAY; Boolean_t mmap_lun = True; tgt_node_t *node = NULL; - int version_maj = XML_VERS_LUN_MAJ, - version_min = XML_VERS_LUN_MIN; + int version_maj = XML_VERS_LUN_MAJ; + int version_min = XML_VERS_LUN_MIN; /* * Clean up from previous call to this function. This occurs if @@ -2398,8 +2400,8 @@ static int find_lu_by_num(const void *v1, const void *v2) { - t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1, - *l2 = (t10_lu_impl_t *)v2; + t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1; + t10_lu_impl_t *l2 = (t10_lu_impl_t *)v2; if (l1->l_targ_lun < l2->l_targ_lun) return (-1); @@ -2416,8 +2418,8 @@ static int find_lu_by_guid(const void *v1, const void *v2) { - t10_lu_common_t *l1 = (t10_lu_common_t *)v1, - *l2 = (t10_lu_common_t *)v2; + t10_lu_common_t *l1 = (t10_lu_common_t *)v1; + t10_lu_common_t *l2 = (t10_lu_common_t *)v2; int i; if (l1->l_guid_len != l2->l_guid_len) { @@ -2445,8 +2447,8 @@ static int find_lu_by_targ(const void *v1, const void *v2) { - t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1, - *l2 = (t10_lu_impl_t *)v2; + t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1; + t10_lu_impl_t *l2 = (t10_lu_impl_t *)v2; if ((uint64_t)(uintptr_t)l1->l_targ < (uint64_t)(uintptr_t)l2->l_targ) return (-1); @@ -2465,8 +2467,8 @@ static int find_cmd_by_addr(const void *v1, const void *v2) { - uint64_t cmd1 = (uint64_t)(uintptr_t)v1, - cmd2 = (uint64_t)(uintptr_t)v2; + uint64_t cmd1 = (uint64_t)(uintptr_t)v1; + uint64_t cmd2 = (uint64_t)(uintptr_t)v2; if (cmd1 < cmd2) return (-1);
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.c Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.c Thu Sep 13 15:17:59 2007 -0700 @@ -49,10 +49,21 @@ #include "t10.h" #include "t10_spc.h" +#include "t10_spc_pr.h" #include "t10_sbc.h" #include "utility.h" /* + * External declarations + */ +void sbc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); +void spc_cmd_pr_in(t10_cmd_t *, uint8_t *, size_t); +void spc_cmd_pr_out(t10_cmd_t *, uint8_t *, size_t); +void spc_cmd_pr_out_data(t10_cmd_t *, emul_handle_t, size_t, char *, size_t); +void spc_pr_read(t10_cmd_t *); +Boolean_t spc_pgr_check(t10_cmd_t *, uint8_t *); + +/* * Forward declarations */ static int sbc_mmap_overlap(const void *v1, const void *v2); @@ -60,7 +71,6 @@ static void sbc_overlap_free(disk_io_t *io); static void sbc_overlap_check(disk_io_t *io); static void sbc_overlap_flush(disk_params_t *d); -static void sbc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); static void sbc_data(t10_cmd_t *cmd, emul_handle_t e, size_t offset, char *data, size_t data_len); static disk_io_t *sbc_io_alloc(t10_cmd_t *c); @@ -160,8 +170,10 @@ { disk_params_t *d = (disk_params_t *)itl->l_common->l_dtype_params; - if (d->d_state == lu_online) + if (d->d_state == lu_online) { itl->l_cmd = sbc_cmd; + itl->l_pgr_read = False; /* Look for PGR data */ + } else itl->l_cmd = spc_cmd_offline; itl->l_data = sbc_data; @@ -171,22 +183,6 @@ void sbc_per_fini(t10_lu_impl_t *itl) { - disk_params_t *d = (disk_params_t *)itl->l_common->l_dtype_params; - t10_lu_impl_t *lu; - - if (d->d_reserve_owner == itl) { - - /* - * Since we currently own the reservation, drop it, - * and restore everyone elses command pointer. - */ - lu = avl_first(&itl->l_common->l_all_open); - do { - lu->l_cmd = sbc_cmd; - lu = AVL_NEXT(&itl->l_common->l_all_open, lu); - } while (lu != NULL); - d->d_reserve_owner = NULL; - } } /* @@ -196,11 +192,19 @@ * | This routine is called from within the SAM-3 Task router. * []---- */ -static void +void sbc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) { scsi_cmd_table_t *e; + /* + * Determine if there is persistent data for this I_T_L Nexus + */ + if (cmd->c_lu->l_pgr_read == False) { + spc_pr_read(cmd); + cmd->c_lu->l_pgr_read = True; + } + e = &cmd->c_lu->l_cmd_table[cdb[0]]; #ifdef FULL_DEBUG queue_prt(mgmtq, Q_STE_IO, "SBC%x LUN%d Cmd %s id=%p\n", @@ -215,34 +219,60 @@ * | sbc_cmd_reserve -- Run commands when another I_T_L has a reservation * []---- */ -static void +void sbc_cmd_reserved(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) { - scsi_cmd_table_t *e; + disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); + sbc_reserve_t *res = &p->d_sbc_reserve; + Boolean_t conflict = False; + /* + * SPC-3, revision 23, Table 31 + * SPC commands that are allowed in the presence of various reservations + */ switch (cdb[0]) { - case SCMD_TEST_UNIT_READY: case SCMD_INQUIRY: + case SCMD_LOG_SENSE_G1: + case SCMD_PERSISTENT_RESERVE_IN: + case SCMD_READ_MEDIA_SERIAL: case SCMD_REPORT_LUNS: - case SCMD_LOG_SENSE_G1: - case SCMD_READ_MEDIA_SERIAL: case SCMD_REPORT_TARGET_PORT_GROUPS: case SCMD_REQUEST_SENSE: - /* - * SPC-2, revision 20, Section 5.5.1 table 10 - * The specification allows these three commands - * to run even through there's a reservation in place. - */ - e = &cmd->c_lu->l_cmd_table[cdb[0]]; -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, "RESERVED: SBC%x LUN%d Cmd %s\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - e->cmd_name == NULL ? "(no name)" : e->cmd_name); -#endif - (*e->cmd_start)(cmd, cdb, cdb_len); + case SCMD_TEST_UNIT_READY: break; + default: + pthread_rwlock_rdlock(&res->res_rwlock); + switch (res->res_type) { + case RT_NONE: + /* conflict = False; */ + break; + case RT_PGR: + conflict = spc_pgr_check(cmd, cdb); + break; + default: + conflict = True; + break; + } + pthread_rwlock_unlock(&res->res_rwlock); + } - default: + queue_prt(mgmtq, Q_PR_IO, + "PGR%x LUN%d CDB:%s - sbc_cmd_reserved(%s:%s)\n", + cmd->c_lu->l_targ->s_targ_num, + cmd->c_lu->l_common->l_num, + cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL + ? "(no name)" + : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name, + res->res_type == RT_PGR ? "PGR" : + res->res_type == RT_NONE ? "" : "unknown", + conflict ? "Conflict" : "Allowed"); + + /* + * If no conflict at this point, allow command + */ + if (conflict == False) { + sbc_cmd(cmd, cdb, cdb_len); + } else { trans_send_complete(cmd, STATUS_RESERVATION_CONFLICT); } } @@ -295,8 +325,8 @@ union scsi_cdb *u = (union scsi_cdb *)cdb; diskaddr_t addr; off_t offset = 0; - uint32_t cnt, - min; + uint32_t cnt; + uint32_t min; disk_io_t *io; void *mmap_data = T10_MMAP_AREA(cmd); uint64_t err_blkno; @@ -984,7 +1014,7 @@ * to contain it's size. */ mode_hdr->length = sizeof (struct mode_header) - 1 + - MODE_BLK_DESC_LENGTH; + MODE_BLK_DESC_LENGTH; mode_hdr->bdesc_length = MODE_BLK_DESC_LENGTH; /* @@ -1057,7 +1087,7 @@ sizeof (struct mode_geometry); np = io->da_data + sizeof (*mode_hdr) + - mode_hdr->bdesc_length; + mode_hdr->bdesc_length; if (io->da_data_len < (sizeof (struct mode_format) + sizeof (struct mode_geometry) + sizeof (struct mode_cache_scsi3) + @@ -1207,8 +1237,8 @@ static void sbc_read_capacity16(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) { - uint64_t capacity, - lba; + uint64_t capacity; + uint64_t lba; int rep_size; /* response data size */ struct scsi_capacity_16 *cap16; disk_params_t *d; @@ -1245,9 +1275,9 @@ } lba = (uint64_t)cdb[2] << 56 | (uint64_t)cdb[3] << 48 | - (uint64_t)cdb[4] << 40 | (uint64_t)cdb[5] << 32 | - (uint64_t)cdb[6] << 24 | (uint64_t)cdb[7] << 16 | - (uint64_t)cdb[8] << 8 | (uint64_t)cdb[9]; + (uint64_t)cdb[4] << 40 | (uint64_t)cdb[5] << 32 | + (uint64_t)cdb[6] << 24 | (uint64_t)cdb[7] << 16 | + (uint64_t)cdb[8] << 8 | (uint64_t)cdb[9]; io = sbc_io_alloc(cmd); @@ -1286,100 +1316,15 @@ /*ARGSUSED*/ static void -sbc_reserve(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - t10_lu_impl_t *lu; - - if (p == NULL) - return; - - if (cdb[1] & 0xe0 || SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if ((p->d_reserve_owner != NULL) && - (p->d_reserve_owner != cmd->c_lu)) { - - trans_send_complete(cmd, STATUS_RESERVATION_CONFLICT); - return; - - } else if (p->d_reserve_owner == cmd->c_lu) { - - /* - * According SPC-2 revision 20, section 7.21.2 - * It shall be permissible for an initiator to - * reserve a logic unit that is currently reserved - * by that initiator - */ - trans_send_complete(cmd, STATUS_GOOD); - } else { - - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - if (lu != cmd->c_lu) - lu->l_cmd = sbc_cmd_reserved; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - p->d_reserve_owner = cmd->c_lu; - trans_send_complete(cmd, STATUS_GOOD); - } -} - -/*ARGSUSED*/ -static void -sbc_release(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - t10_lu_impl_t *lu; - - if (p == NULL) - return; - - if (cdb[1] & 0xe0 || cdb[3] || cdb[4] || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if (p->d_reserve_owner == NULL) { - - /* - * If nobody is the owner this command is successful. - */ - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - /* - * At this point the only way to get in here is to be the owner - * of the reservation. - */ - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_cmd = sbc_cmd; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - p->d_reserve_owner = NULL; - trans_send_complete(cmd, STATUS_GOOD); -} - -/*ARGSUSED*/ -static void sbc_verify(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) { /*LINTED*/ union scsi_cdb *u = (union scsi_cdb *)cdb; diskaddr_t addr; - uint32_t cnt, - chk_size; - uint64_t sz, - err_blkno; + uint32_t cnt; + uint32_t chk_size; + uint64_t sz; + uint64_t err_blkno; Boolean_t bytchk; char *chk_block; disk_io_t *io; @@ -1572,6 +1517,7 @@ spc_sense_create(cmd, KEY_MISCOMPARE, 0); spc_sense_ascq(cmd, SPC_ASC_DATA_PATH, SPC_ASCQ_DATA_PATH); trans_send_complete(cmd, STATUS_CHECK); + free(on_disk_buf); sbc_io_free(io); return; } @@ -1579,6 +1525,7 @@ spc_sense_create(cmd, KEY_MISCOMPARE, 0); spc_sense_ascq(cmd, SPC_ASC_MISCOMPARE, SPC_ASCQ_MISCOMPARE); trans_send_complete(cmd, STATUS_CHECK); + free(on_disk_buf); sbc_io_free(io); return; } @@ -1776,8 +1723,8 @@ static int sbc_mmap_overlap(const void *v1, const void *v2) { - disk_io_t *d1 = (disk_io_t *)v1, - *d2 = (disk_io_t *)v2; + disk_io_t *d1 = (disk_io_t *)v1; + disk_io_t *d2 = (disk_io_t *)v2; if ((d1->da_data + d1->da_data_len) < d2->da_data) return (-1); @@ -1904,8 +1851,8 @@ { spc_unsupported, NULL, NULL, NULL }, { spc_unsupported, NULL, NULL, NULL }, { spc_mselect, spc_mselect_data, NULL, "MODE_SELECT" }, - { sbc_reserve, NULL, NULL, "RESERVE" }, - { sbc_release, NULL, NULL, "RELEASE" }, + { spc_unsupported, NULL, NULL, NULL }, + { spc_unsupported, NULL, NULL, NULL }, { spc_unsupported, NULL, NULL, NULL }, { spc_unsupported, NULL, NULL, NULL }, { sbc_msense, NULL, NULL, "MODE_SENSE" }, @@ -1984,8 +1931,8 @@ { spc_unsupported, NULL, NULL, NULL }, { spc_unsupported, NULL, NULL, NULL }, { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "PERSISTENT_IN" }, - { spc_unsupported, NULL, NULL, "PERSISTENT_OUT" }, + { spc_cmd_pr_in, NULL, NULL, "PERSISTENT_RESERVE_IN" }, + { spc_cmd_pr_out, spc_cmd_pr_out_data, NULL, "PERSISTENT_RESERVE_OUT" }, /* 0x60 -- 0x6f */ { spc_unsupported, NULL, NULL, NULL },
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.h Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.h Thu Sep 13 15:17:59 2007 -0700 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -120,8 +120,7 @@ Boolean_t d_fast_write; t10_lu_state_t d_state; - - t10_lu_impl_t *d_reserve_owner; + sbc_reserve_t d_sbc_reserve; } disk_params_t; typedef struct disk_io {
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_spc.c Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/t10_spc.c Thu Sep 13 15:17:59 2007 -0700 @@ -51,7 +51,7 @@ #include "t10_spc.h" #include "target.h" -static void spc_free(emul_handle_t id); +void spc_free(emul_handle_t id); /* * []---- @@ -134,13 +134,13 @@ void spc_inquiry(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) { - uint8_t *rsp_buf, - *rbp; /* temporary var */ + uint8_t *rsp_buf; + uint8_t *rbp; /* temporary var */ struct scsi_inquiry *inq; - uint32_t len, - page83_len, - rqst_len, - rtn_len; + uint32_t len; + uint32_t page83_len; + uint32_t rqst_len; + uint32_t rtn_len; struct vpd_hdr *vhp; struct vpd_desc vd; size_t scsi_len; @@ -188,7 +188,7 @@ */ scsi_len = ((strlen(cmd->c_lu->l_targ->s_targ_base) + 1) + 3) & ~3; page83_len = (sizeof (struct vpd_desc) * 6) + scsi_len + - (lu->l_guid_len * 3) + (sizeof (uint32_t) * 2); + (lu->l_guid_len * 3) + (sizeof (uint32_t) * 2); /* * We always allocate enough space so that the code can create @@ -396,8 +396,8 @@ bcopy(&vd, rbp, sizeof (vd)); rbp += sizeof (vd); - rbp[2] = hibyte(loword(cmd->c_lu->l_targ->s_tp_grp)); - rbp[3] = lobyte(loword(cmd->c_lu->l_targ->s_tp_grp)); + rbp[2] = hibyte(loword(cmd->c_lu->l_targ->s_tpgt)); + rbp[3] = lobyte(loword(cmd->c_lu->l_targ->s_tpgt)); rbp += vd.len; /* ---- VPD descriptor ---- */ @@ -588,16 +588,16 @@ { int expected_data; uint8_t *buf = NULL; - int entries = 0, - len, - len_network, - select, - lun_idx, - lun_val; + int entries = 0; + int len; + int len_network; + int select; + int lun_idx; + int lun_val; char *str; - tgt_node_t *targ, - *lun_list, - *lun; + tgt_node_t *targ; + tgt_node_t *lun_list; + tgt_node_t *lun; /* * SPC-3 Revision 21c section 6.21 @@ -702,9 +702,9 @@ rtpg_hdr_t *r; rtpg_desc_t *dp; rtpg_targ_desc_t *tp; - int rqst_len, - alloc_len, - i; + int rqst_len; + int alloc_len; + int i; t10_lu_common_t *lu = cmd->c_lu->l_common; t10_lu_impl_t *lu_per; @@ -778,8 +778,8 @@ tp = &dp->targ_list[0]; lu_per = avl_first(&lu->l_all_open); do { - tp->rel_tpi[0] = hibyte(loword(lu_per->l_targ->s_tp_grp)); - tp->rel_tpi[1] = lobyte(loword(lu_per->l_targ->s_tp_grp)); + tp->rel_tpi[0] = hibyte(loword(lu_per->l_targ->s_tpgt)); + tp->rel_tpi[1] = lobyte(loword(lu_per->l_targ->s_tpgt)); lu_per = AVL_NEXT(&lu->l_all_open, lu_per); tp++; } while (lu_per != NULL); @@ -815,7 +815,7 @@ trans_send_complete(cmd, STATUS_GOOD); } -static void +void spc_free(emul_handle_t id) { free(id); @@ -1139,14 +1139,13 @@ * SAM-3 revision 14, Section 4.9.7. * 14-bit flat address space. */ - buf[0] = SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE | - (lun >> 8 & 0x3f); + buf[0] = SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE | (lun >> 8 & 0x3f); buf[1] = lun & 0xff; } else if (select_field == SCSI_REPORTLUNS_SELECT_ALL) { buf[0] = SCSI_REPORTLUNS_ADDRESS_EXTENDED_UNIT | - SCSI_REPORTLUNS_ADDRESS_EXTENDED_6B; + SCSI_REPORTLUNS_ADDRESS_EXTENDED_6B; /* * 32-bit limitation. This format should be able to * handle a 40-bit LUN.
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_spc.h Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/t10_spc.h Thu Sep 13 15:17:59 2007 -0700 @@ -20,15 +20,19 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#ifndef _SPC_H -#define _SPC_H +#ifndef _T10_SPC_H +#define _T10_SPC_H #pragma ident "%Z%%M% %I% %E% SMI" +#ifdef __cplusplus +extern "C" { +#endif + /* * []------------------------------------------------------------------[] * | SPC-3 | @@ -98,33 +102,60 @@ * | by the code. | * []------------------------------------------------------------------[] */ -#define SPC_ASC_INVALID_CDB 0x24 -#define SPC_ASCQ_INVALID_CDB 0x00 -#define SPC_ASC_PWR_RESET 0x29 -#define SPC_ASCQ_PWR_RESET 0x00 -#define SPC_ASC_PWR_ON 0x29 -#define SPC_ASCQ_PWR_ON 0x01 -#define SPC_ASC_BUS_RESET 0x29 -#define SPC_ASCQ_BUS_RESET 0x02 #define SPC_ASC_FM_DETECTED 0x00 /* file-mark detected */ #define SPC_ASCQ_FM_DETECTED 0x01 + #define SPC_ASC_EOP 0x00 /* end-of-partition/medium detected */ #define SPC_ASCQ_EOP 0x02 -#define SPC_ASC_WRITE_ERROR 0x0c -#define SPC_ASCQ_WRITE_ERROR 0x00 -#define SPC_ASC_CAP_CHANGE 0x2a -#define SPC_ASCQ_CAP_CHANGE 0x09 + #define SPC_ASC_IN_PROG 0x04 #define SPC_ASCQ_IN_PROG 0x07 -#define SPC_ASC_DATA_PATH 0x41 -#define SPC_ASCQ_DATA_PATH 0x00 + +#define SPC_ASC_WRITE_ERROR 0x0c +#define SPC_ASCQ_WRITE_ERROR 0x00 + +#define SPC_ASC_PARAM_LIST_LEN 0x1a /* Parameter List Length Error */ +#define SPC_ASCQ_PARAM_LIST_LEN 0x00 + #define SPC_ASC_MISCOMPARE 0x1d #define SPC_ASCQ_MISCOMPARE 0x00 + #define SPC_ASC_INVALID_LU 0x20 #define SPC_ASCQ_INVALID_LU 0x09 + #define SPC_ASC_BLOCK_RANGE 0x21 #define SPC_ASCQ_BLOCK_RANGE 0x00 +#define SPC_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26 +#define SPC_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST 0x00 + +#define SPC_ASC_INVALID_CDB 0x24 +#define SPC_ASCQ_INVALID_CDB 0x00 + +#define SPC_ASC_PARAMETERS_CHANGED 0x2a +#define SPC_ASCQ_RES_PREEMPTED 0x03 +#define SPC_ASCQ_RES_RELEASED 0x04 + +#define SPC_ASC_PWR_RESET 0x29 +#define SPC_ASCQ_PWR_RESET 0x00 + +#define SPC_ASC_PWR_ON 0x29 +#define SPC_ASCQ_PWR_ON 0x01 + +#define SPC_ASC_BUS_RESET 0x29 +#define SPC_ASCQ_BUS_RESET 0x02 + +#define SPC_ASC_CAP_CHANGE 0x2a +#define SPC_ASCQ_CAP_CHANGE 0x09 + +#define SPC_ASC_DATA_PATH 0x41 +#define SPC_ASCQ_DATA_PATH 0x00 + +#define SPC_ASC_MEMORY_OUT_OF 0x55 /* Auxillary Memory Out Of Space */ +#define SPC_ASCQ_MEMORY_OUT_OF 0x00 +#define SPC_ASCQ_RESERVATION_FAIL 0x02 + + /* * []------------------------------------------------------------------[] * | SAM-3, revision 14, section 5.2 - Command descriptor block (CDB) | @@ -417,4 +448,8 @@ #define SCSI_REPORTLUNS_ADDRESS_EXTENDED_MASK 0x30 #define SCSI_REPORTLUNS_SELECT_ALL 0x02 -#endif /* _SPC_H */ +#ifdef __cplusplus +} +#endif + +#endif /* _T10_SPC_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c Thu Sep 13 15:17:59 2007 -0700 @@ -0,0 +1,1964 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * []------------------------------------------------------------------[] + * | Implementation of SPC-3 Persistent Reserve emulation | + * []------------------------------------------------------------------[] + */ +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/asynch.h> +#include <sys/param.h> +#include <sys/sysmacros.h> +#include <strings.h> +#include <unistd.h> +#include <pthread.h> +#include <assert.h> + +#include <sys/scsi/generic/sense.h> +#include <sys/scsi/generic/status.h> +#include <sys/scsi/generic/inquiry.h> +#include <sys/scsi/generic/mode.h> +#include <sys/scsi/generic/commands.h> +#include <sys/scsi/generic/persist.h> + +#include "t10.h" +#include "t10_spc.h" +#include "t10_spc_pr.h" +#include "t10_sbc.h" +#include "target.h" + +/* + * External declarations + */ +extern target_queue_t *mgmtq; +void spc_free(emul_handle_t id); +void sbc_cmd(t10_cmd_t *, uint8_t *, size_t); +void sbc_cmd_reserved(t10_cmd_t *, uint8_t *, size_t); + +/* + * Forward declarations + */ +static spc_pr_key_t *spc_pr_key_find(scsi3_pgr_t *, uint64_t, char *, char *); +static spc_pr_key_t *spc_pr_key_alloc(scsi3_pgr_t *, uint64_t, char *, char *); +static spc_pr_rsrv_t *spc_pr_rsrv_find(scsi3_pgr_t *, uint64_t, char *, char *); +static spc_pr_rsrv_t *spc_pr_rsrv_alloc(scsi3_pgr_t *, uint64_t, char *, char *, + uint8_t, uint8_t); + +static void spc_pr_key_free(scsi3_pgr_t *, spc_pr_key_t *); +static void spc_pr_rsrv_free(scsi3_pgr_t *, spc_pr_rsrv_t *); +static void spc_pr_rsrv_release(t10_cmd_t *, scsi3_pgr_t *, spc_pr_rsrv_t *); + +static int spc_pr_out_register(t10_cmd_t *, void *, size_t); +static int spc_pr_out_reserve(t10_cmd_t *, void *, size_t); +static int spc_pr_out_release(t10_cmd_t *, void *, size_t); +static int spc_pr_out_clear(t10_cmd_t *, void *, size_t); +static int spc_pr_out_preempt(t10_cmd_t *, void *, size_t); +static int spc_pr_out_register_and_move(t10_cmd_t *, void *, size_t); + +static int spc_pr_in_readkeys(char *, scsi3_pgr_t *, void *, uint16_t); +static int spc_pr_in_readrsrv(char *, scsi3_pgr_t *, void *, uint16_t); +static int spc_pr_in_repcap(char *, scsi3_pgr_t *, void *, uint16_t); +static int spc_pr_in_fullstat(char *, scsi3_pgr_t *, void *, uint16_t); + +Boolean_t spc_pr_write(t10_cmd_t *); +static void spc_pr_erase(scsi3_pgr_t *); +static void spc_pr_initialize(scsi3_pgr_t *); + +/* + * []---- + * | spc_pgr_is_conflicting + * | PGR reservation conflict checking. + * | SPC-3, Revision 23, Table 31 + * []---- + */ +static int +spc_pgr_is_conflicting(uint8_t *cdb, uint_t type) +{ + Boolean_t conflict = False; + + switch (cdb[0]) { + case SCMD_FORMAT: + case SCMD_EXTENDED_COPY: + case SCMD_LOG_SELECT_G1: + case SCMD_MODE_SELECT: + case SCMD_MODE_SELECT_G1: + case SCMD_MODE_SENSE: + case SCMD_MODE_SENSE_G1: + case SCMD_READ_ATTRIBUTE: + case SCMD_READ_BUFFER: + case SCMD_GDIAG: /* SCMD_RECEIVE_DIAGNOSTIC_RESULTS */ + case SCMD_SDIAG: /* SCMD_SEND_DIAGNOSTIC_RESULTS */ + case SCMD_WRITE_ATTRIBUTE: + case SCMD_WRITE_BUFFER: + conflict = True; + break; + + case SCMD_DOORLOCK: /* SCMD_PREVENT_ALLOW_MEDIA_REMOVAL */ + /* + * As per SPC-3, Revision 23, Table 31 + * (prevent <> 0) + */ + conflict = (cdb[4] & 0x1) ? True: False; + break; + + case SCMD_REPORT_TARGET_PORT_GROUPS: /* SCMD_REPORT_ */ + /* + * As pee SPC-3, Revision 23, Section 6.23 + */ + switch ((cdb[1] & 0x03)) { + /* SCMD_REPORT_SUPPORTED_OPERATION_CODES */ + case 0x0c: + /* SCMD_REPORT_SUPPORTED_MANAGEMENT_FUNCTIONS */ + case 0x0d: + + conflict = True; + break; + } + break; + + case SCMD_SET_DEVICE: + /* + * SPC-3, Revision 23, Section 6.29 + */ + switch ((cdb[1] & 0x1F)) { + case SCMD_SET_DEVICE_IDENTIFIER: + case SCMD_SET_PRIORITY: + case SCMD_SET_TARGET_PORT_GROUPS: + case SCMD_SET_TIMESTAMP: + conflict = True; + break; + } + break; + + case SCMD_READ: + case SCMD_READ_G1: + case SCMD_READ_G4: + /* + * Exclusive Access, and EA Registrants Only + */ + if (type == PGR_TYPE_EX_AC || type == PGR_TYPE_EX_AC_RO) + conflict = True; + break; + } + + return (conflict); +} + +/* + * []---- + * | spc_pgr_check -- PERSISTENT_RESERVE {IN|OUT} check of I_T_L + * | Refer to SPC-3, Section ?.?, Tables ?? and ?? + * []---- + */ +Boolean_t +spc_pgr_check(t10_cmd_t *cmd, uint8_t *cdb) +{ + disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); + sbc_reserve_t *res = &p->d_sbc_reserve; + scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; + spc_pr_rsrv_t *rsrv = NULL; + Boolean_t conflict = False; + + /* + * If no reservations exist, allow all remaining command types. + */ + assert(res->res_type == RT_PGR); + if (pgr->pgr_numrsrv == 0) { + conflict = False; + goto done; + } + + /* + * 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. + */ + if (!(rsrv = spc_pr_rsrv_find(pgr, 0, "", T10_PGR_TNAME(cmd)))) { + queue_prt(mgmtq, Q_PR_ERRS, "PGR%x Reserved on other port\n", + "\t%s:%s\n", cmd->c_lu->l_targ->s_targ_num, + T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)); + conflict = True; + goto done; + } + + /* + * Check the command against the reservation type for this port. + */ + switch (rsrv->r_type) { + case PGR_TYPE_WR_EX: /* Write Exclusive */ + case PGR_TYPE_EX_AC: /* Exclusive Access */ + if (strcmp(T10_PGR_INAME(cmd), rsrv->r_i_name) == 0) + conflict = False; + else + conflict = spc_pgr_is_conflicting(cdb, + rsrv->r_type); + break; + case PGR_TYPE_WR_EX_RO: /* Write Exclusive, Registrants Only */ + case PGR_TYPE_EX_AC_RO: /* Exclusive Access, Registrants Only */ + if (spc_pr_key_find( + pgr, 0, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd))) + conflict = False; + else + conflict = spc_pgr_is_conflicting(cdb, + rsrv->r_type); + break; + case PGR_TYPE_WR_EX_AR: /* Write Exclusive, All Registrants */ + case PGR_TYPE_EX_AC_AR: /* Exclusive Access, All Registrants */ + if (spc_pr_key_find(pgr, 0, "", T10_PGR_TNAME(cmd))) + conflict = False; + else + conflict = spc_pgr_is_conflicting(cdb, + rsrv->r_type); + break; + default: + conflict = True; + break; + } + +done: + queue_prt(mgmtq, Q_PR_IO, "PGR%x LUN%d CDB:%s - spc_pgr_check(%s:%s)\n", + cmd->c_lu->l_targ->s_targ_num, + cmd->c_lu->l_common->l_num, + cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL + ? "(no name)" + : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name, + (rsrv == NULL) + ? "<none>" + : (rsrv->r_type == PR_IN_READ_KEYS) + ? "Write Exclusive" + : (rsrv->r_type == PGR_TYPE_WR_EX) + ? "Exclusive Access" + : (rsrv->r_type == PGR_TYPE_EX_AC) + ? "Report capabilties" + : (rsrv->r_type == PGR_TYPE_WR_EX_RO) + ? "Write Exclusive, Registrants Only" + : (rsrv->r_type == PGR_TYPE_EX_AC_RO) + ? "Exclusive Access, Registrants Only" + : (rsrv->r_type == PGR_TYPE_WR_EX_AR) + ? "Write Exclusive, All Registrants" + : (rsrv->r_type == PGR_TYPE_EX_AC_AR) + ? "Exclusive Access, All Registrants" + : "Uknown reservation type", + (conflict) ? "Conflict" : "Allowed"); + + return (conflict); +} + +/* + * []---- + * | spc_cmd_pr_in -- PERSISTENT_RESERVE IN + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +/*ARGSUSED*/ +void +spc_cmd_pr_in(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) +{ + scsi_cdb_prin_t *p_prin = (scsi_cdb_prin_t *)cdb; + disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); + sbc_reserve_t *res = &p->d_sbc_reserve; + scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; + uint16_t alen; + size_t len = 0; + void *buf; + + /* + * Information obtained from: + * SPC-3, Revision 23 + * 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 + * true. + * (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. + */ + if ((p_prin->action >= 0x4) || p_prin->resbits || p_prin->resbytes[0] || + p_prin->resbytes[1] || p_prin->resbytes[2] || p_prin->resbytes[3] || + p_prin->resbytes[4] || p_prin->control) { + spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); + spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); + trans_send_complete(cmd, STATUS_CHECK); + return; + } + + /* + * Information obtained from: + * SPC-3, Revision 23 + * 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. + */ + if ((alen = SCSI_READ16(p_prin->alloc_len)) == 0) { + queue_prt(mgmtq, Q_PR_ERRS, + "PGR%x LUN%d CDB:%s - spc_cmd_pr_in, len = 0\n", + cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, + cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL + ? "(no name)" + : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name); + + trans_send_complete(cmd, STATUS_GOOD); + return; + } + + /* + * Allocate space with an alignment that will work for any casting. + */ + if ((buf = memalign(sizeof (void *), alen)) == NULL) { + /* + * Lack of memory is not fatal, just too busy + */ + trans_send_complete(cmd, STATUS_BUSY); + return; + } else { + bzero(buf, alen); + } + + /* + * Start processing, lock reservation + */ + pthread_rwlock_rdlock(&res->res_rwlock); + + queue_prt(mgmtq, Q_PR_NONIO, "PGR%x LUN%d action:%s\n", + cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, + (p_prin->action == PR_IN_READ_KEYS) + ? "Read keys" + : (p_prin->action == PR_IN_READ_RESERVATION) + ? "Read reservation" + : (p_prin->action == PR_IN_REPORT_CAPABILITIES) + ? "Report capabilties" + : (p_prin->action == PR_IN_READ_FULL_STATUS) + ? "Read full status" + : "Uknown"); + + /* + * Per SPC-3, Revision 23, Table 102, validate ranget of service actions + */ + switch (p_prin->action) { + case PR_IN_READ_KEYS: + len = spc_pr_in_readkeys( + T10_PGR_TNAME(cmd), pgr, buf, alen); + break; + case PR_IN_READ_RESERVATION: + len = spc_pr_in_readrsrv( + T10_PGR_TNAME(cmd), pgr, buf, alen); + break; + case PR_IN_REPORT_CAPABILITIES: + len = spc_pr_in_repcap( + T10_PGR_TNAME(cmd), pgr, buf, alen); + break; + case PR_IN_READ_FULL_STATUS: + len = spc_pr_in_fullstat( + T10_PGR_TNAME(cmd), pgr, buf, alen); + break; + } + + /* + * Complete processing, unlock reservation + */ + pthread_rwlock_unlock(&res->res_rwlock); + + /* + * Now send the selected Persistent Reservation response back + */ + if (trans_send_datain(cmd, buf, len, 0, spc_free, True, buf) == False) + trans_send_complete(cmd, STATUS_BUSY); +} + +/* + * []---- + * | spc_pr_in_readkey - + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +static int +spc_pr_in_readkeys(char *transportID, scsi3_pgr_t *pgr, void *bp, + uint16_t alloc_len) +{ + int i = 0, max_buf_keys, hsize; + scsi_prin_readrsrv_t *buf = (scsi_prin_readrsrv_t *)bp; + spc_pr_key_t *key; + + hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len); + max_buf_keys = ((int)alloc_len - hsize) / sizeof (key->k_key); + + queue_prt(mgmtq, Q_PR_NONIO, + "PGRIN readkeys - transportID=%s\n", transportID); + + if (pgr->pgr_numkeys) + for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; + key != (spc_pr_key_t *)&pgr->pgr_keylist; + key = (spc_pr_key_t *)key->k_link.lnk_fwd) { + + if (strcmp(key->k_transportID, transportID)) + continue; + + if (i < max_buf_keys) { + SCSI_WRITE64(&buf->key_list.service_key[i], key->k_key); + queue_prt(mgmtq, Q_PR_NONIO, + "PGRIN readkeys - key:%016lx, i_name:%s\n", + key->k_key, key->k_i_name); + i++; + } + else + break; /* No room left, leave now */ + } + + SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation); + SCSI_WRITE32(buf->add_len, i * sizeof (key->k_key)); + + return (hsize + min(i, max_buf_keys) * sizeof (key->k_key)); +} + +/* + * []---- + * | spc_pr_in_readresv - + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +static int +spc_pr_in_readrsrv( + char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len) +{ + int i = 0, max_buf_rsrv, hsize; + scsi_prin_readrsrv_t *buf = (scsi_prin_readrsrv_t *)bp; + scsi_prin_rsrvdesc_t *desc; + spc_pr_rsrv_t *rsrv; + + hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len); + max_buf_rsrv = ((int)alloc_len - hsize) / sizeof (scsi_prin_rsrvdesc_t); + + queue_prt(mgmtq, Q_PR_NONIO, + "PGRIN readrsrv - transportID=%s\n", transportID); + + if (pgr->pgr_numrsrv) + for (rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; + rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; + rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd) { + + if (strcmp(rsrv->r_transportID, transportID)) + continue; + + if (i < max_buf_rsrv) { + desc = &buf->key_list.res_key_list[i]; + SCSI_WRITE64(desc->reservation_key, rsrv->r_key); + desc->scope = rsrv->r_scope; + desc->type = rsrv->r_type; + + queue_prt(mgmtq, Q_PR_NONIO, + "PGRIN readrsrv - " + "key:%016lx i_name:%s scope:%d type:%d \n", + rsrv->r_key, rsrv->r_i_name, + rsrv->r_scope, rsrv->r_type); + + i++; + } + else + break; /* No room left, leave now */ + } + + SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation); + SCSI_WRITE32(buf->add_len, i * sizeof (scsi_prin_rsrvdesc_t)); + + return (hsize + min(i, max_buf_rsrv)* sizeof (scsi_prin_rsrvdesc_t)); +} + +/* + * []---- + * | spc_pr_in_repcap - + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +/* + */ +static int +spc_pr_in_repcap( + char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len) +{ + scsi_prin_rpt_cap_t *buf = (scsi_prin_rpt_cap_t *)bp; + + buf->crh = 0; /* Supports Reserve / Release */ + 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 */ + buf->ptpl_a = pgr_persist; /* Persist Though Power Loss Active */ + buf->pr_type.wr_ex = 1; /* Write Exclusve */ + buf->pr_type.ex_ac = 1; /* Exclusive Access */ + buf->pr_type.wr_ex_ro = 1; /* Write Exclusive Registrants Only */ + buf->pr_type.ex_ac_ro = 1; /* Exclusive Access Registrants Only */ + buf->pr_type.wr_ex_ar = 1; /* Write Exclusive All Registrants */ + buf->pr_type.ex_ac_ar = 1; /* Exclusive Access All Registrants */ + + SCSI_WRITE16(buf->length, sizeof (scsi_prin_rpt_cap_t)); + + return (sizeof (scsi_prin_rpt_cap_t)); +} + +/* + * []---- + * | spc_pr_in_fullstat - + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +/* + */ +static int +spc_pr_in_fullstat( + char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len) +{ + int i = 0, max_buf_rsrv, hsize; + spc_pr_rsrv_t *rsrv; + scsi_prin_full_status_t *buf = (scsi_prin_full_status_t *)bp; + + hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len); + max_buf_rsrv = ((int)alloc_len - hsize) / + sizeof (scsi_prin_full_status_t); + + if (pgr->pgr_numrsrv) + for (i = 0, rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; + rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; + rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd) { + + if (i < max_buf_rsrv) { + SCSI_WRITE64(buf->full_desc[i].reservation_key, + rsrv->r_key); + buf->full_desc[i].all_tg_pt = 1; + buf->full_desc[i].r_holder = + strcmp(rsrv->r_transportID, transportID) ? 0 : 1; + buf->full_desc[i].scope = rsrv->r_scope; + buf->full_desc[i].type = rsrv->r_type; + SCSI_WRITE16(buf->full_desc[i].rel_tgt_port_id, 0); + SCSI_WRITE32(buf->full_desc[i].add_len, + sizeof (scsi_transport_id_t)); + buf->full_desc[i].trans_id.protocol_id = + iSCSI_PROTOCOL_ID; + buf->full_desc[i].trans_id.format_code = + WW_UID_DEVICE_NAME; + SCSI_WRITE16(buf->full_desc[i].trans_id.add_len, 0); + sprintf(buf->full_desc[i].trans_id.iscsi_name, ""); + + i++; + } + else + break; /* No room left, leave now */ + + } + + SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation); + SCSI_WRITE32(buf->add_len, i * sizeof (scsi_prin_rsrvdesc_t)); + + return (hsize + min(i, max_buf_rsrv) * sizeof (scsi_prin_rsrvdesc_t)); + +} + +/* + * []---- + * | spc_cmd_pr_out -- PERSISTENT_RESERVE OUT + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +/*ARGSUSED*/ +void +spc_cmd_pr_out(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) +{ + scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cdb; + size_t len; + void *buf; + + /* + * Information obtained from: + * SPC-3, Revision 23 + * 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 + * true. + * (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. + */ + if ((p_prout->action >= 0x8) || p_prout->resbits || + (p_prout->type >= 0x9) || + (p_prout->scope >= 0x3) || p_prout->control) { + spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); + spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); + trans_send_complete(cmd, STATUS_CHECK); + return; + } + + /* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.12 PERSISTENCE RESERVE OUT + * Acquire ALLOCATION LENGTH from bytes 5 thru 8 + */ + len = SCSI_READ32(p_prout->param_len); + + /* + * 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 + */ + if ((p_prout->action != PR_OUT_REGISTER_MOVE) && (len != 24)) { + spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); + spc_sense_ascq(cmd, SPC_ASC_PARAM_LIST_LEN, 0x00); + trans_send_complete(cmd, STATUS_CHECK); + return; + } + + /* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.11.3.3 Persistent Reservation Scope + * SCOPE field shall be set to LU_SCOPE + */ + if (p_prout->scope != PR_LU_SCOPE) { + spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); + spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); + trans_send_complete(cmd, STATUS_CHECK); + return; + } + + /* + * Allocate space with an alignment that will work for any casting. + */ + if ((buf = memalign(sizeof (void *), len)) == NULL) { + /* + * Lack of memory is not fatal, just too busy + */ + trans_send_complete(cmd, STATUS_BUSY); + return; + } + + /* + * Now request the Persistent Reserve OUT parameter list + */ + if (trans_rqst_dataout(cmd, buf, len, 0, buf, spc_free) == False) + trans_send_complete(cmd, STATUS_BUSY); +} + +/* + * []---- + * | spc_cmd_pr_out_data -- DataIn phase of PERSISTENT_RESERVE OUT command + * []---- + */ +/*ARGSUSED*/ +void +spc_cmd_pr_out_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, + size_t data_len) +{ + scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; + disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); + sbc_reserve_t *res = &p->d_sbc_reserve; + scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; + scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; + t10_lu_impl_t *lu; + int status; + + /* + * If this is the first time using the persistance data, + * initialize the reservation and resource key queues + */ + pthread_rwlock_wrlock(&res->res_rwlock); + if (pgr->pgr_rsrvlist.lnk_fwd == NULL) { + spc_pr_initialize(pgr); + } + + queue_prt(mgmtq, Q_PR_NONIO, "PGR%x LUN%d action:%s\n", + cmd->c_lu->l_targ->s_targ_num, + cmd->c_lu->l_common->l_num, + (p_prout->action == PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY) + ? "Register & ignore existing key" + : (p_prout->action == PR_OUT_REGISTER) + ? "Register" + : (p_prout->action == PR_OUT_RESERVE) + ? "Reserve" + : (p_prout->action == PR_OUT_RELEASE) + ? "Release" + : (p_prout->action == PR_OUT_CLEAR) + ? "Clear" + : (p_prout->action == PR_OUT_PREEMPT_ABORT) + ? "Preempt & abort" + : (p_prout->action == PR_OUT_PREEMPT) + ? "Preempt" + : (p_prout->action == PR_OUT_REGISTER_MOVE) + ? "Register & move" + : "Uknown"); + + /* + * Now process the action. + */ + switch (p_prout->action) { + case PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY: + case PR_OUT_REGISTER: + /* + * PR_OUT_REGISTER_IGNORE differs from PR_OUT_REGISTER + * in that the reservation_key is ignored. + */ + status = spc_pr_out_register(cmd, data, data_len); + break; + + case PR_OUT_RESERVE: + status = spc_pr_out_reserve(cmd, data, data_len); + break; + + case PR_OUT_RELEASE: + status = spc_pr_out_release(cmd, data, data_len); + break; + + case PR_OUT_CLEAR: + status = spc_pr_out_clear(cmd, data, data_len); + break; + + case PR_OUT_PREEMPT_ABORT: + case PR_OUT_PREEMPT: + /* + * PR_OUT_PREEMPT_ABORT differs from PR_OUT_PREEMPT + * in that all current acitivy for the preempted + * Initiators will be terminated. + */ + status = spc_pr_out_preempt(cmd, data, data_len); + break; + + case PR_OUT_REGISTER_MOVE: + /* + * PR_OUT_REGISTER_MOVE registers a key for another I_T + */ + status = spc_pr_out_register_and_move(cmd, data, data_len); + break; + } + + /* + * Check status of action performed. + */ + if (status == STATUS_CHECK) { + /* + * Check condition required. + */ + pthread_rwlock_unlock(&res->res_rwlock); + spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); + spc_sense_ascq(cmd, cmd->c_lu->l_asc, cmd->c_lu->l_ascq); + trans_send_complete(cmd, STATUS_CHECK); + return; + } + + /* + * Handle Failed processing status + */ + if (status != STATUS_GOOD) { + pthread_rwlock_unlock(&res->res_rwlock); + trans_send_complete(cmd, status); + return; + } + + /* + * Successful, bump the PRgeneration value + */ + if (p_prout->action != PR_OUT_RESERVE && + p_prout->action != PR_OUT_RELEASE) + pgr->pgr_generation++; + + /* + * If Activate Persist Through Power Loss (APTPL) is set, persist + * this PGR data on disk + */ + if (plist->aptpl || pgr->pgr_aptpl) + spc_pr_write(cmd); + + /* + * When the last registration is removed, PGR is no longer + * active and we must reset the reservation type. + */ + if ((pgr->pgr_numkeys == 0) && (pgr->pgr_numrsrv == 0)) { + res->res_type = RT_NONE; + pgr->pgr_aptpl = 0; + } else { + res->res_type = RT_PGR; + } + + /* + * Set the command dispatcher according to the reservation type + */ + (void) pthread_mutex_lock(&cmd->c_lu->l_common->l_common_mutex); + lu = avl_first(&cmd->c_lu->l_common->l_all_open); + do { + lu->l_cmd = (res->res_type == RT_NONE) + ? sbc_cmd : sbc_cmd_reserved; + lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); + } while (lu != NULL); + (void) pthread_mutex_unlock(&cmd->c_lu->l_common->l_common_mutex); + + /* + * Processing is complete, release mutex + */ + pthread_rwlock_unlock(&res->res_rwlock); + + /* + * Send back a succesful response + */ + trans_send_complete(cmd, STATUS_GOOD); +} + +/* + * []---- + * | spc_pr_out_register + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +static int +spc_pr_out_register(t10_cmd_t *cmd, void *data, size_t data_len) +{ + scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; + scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; + disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); + sbc_reserve_t *res = &p->d_sbc_reserve; + scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; + spc_pr_rsrv_t *rsrv; + spc_pr_key_t *key; + uint64_t reservation_key; + uint64_t service_key; + t10_lu_impl_t *lu; + t10_targ_impl_t *ti; + + /* + * Validate Persistent Reserver Out parameter list + */ + if (plist->obsolete1[0] || plist->obsolete1[1] || + plist->obsolete1[2] || plist->obsolete1[3] || + plist->resbits1 || plist->resbits2 || plist->resbytes1 || + plist->obsolete2[0] || plist->obsolete2[1]) { + cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST; + cmd->c_lu->l_asc = SPC_ASC_INVALID_CDB; + cmd->c_lu->l_ascq = 0; + return (STATUS_CHECK); + } + + /* + * Determine if Activate Persist Trhough Power Loss (APTPL) + * is valid for this device server. + */ + if (plist->aptpl && (pgr_persist == 0)) { + /* pgr - define SCSI-3 error codes */ + cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST; + cmd->c_lu->l_asc = SPC_ASC_INVALID_FIELD_IN_PARAMETER_LIST; + cmd->c_lu->l_ascq = 0; + return (STATUS_CHECK); + } + + /* + * Get reservation values + */ + reservation_key = SCSI_READ64(plist->reservation_key); + service_key = SCSI_READ64(plist->service_key); + + queue_prt(mgmtq, Q_PR_NONIO, + "PGR%x LUN%d register reservation:%016lx, key:%016lx\n", + cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, + reservation_key, service_key); + + /* + * We may need register all initiators, depending on ALL_TG_TP + */ + lu = avl_first(&cmd->c_lu->l_common->l_all_open); + do { + /* + * Find specified key + */ + ti = lu->l_targ; + key = spc_pr_key_find(pgr, 0, ti->s_i_name, ti->s_targ_base); + if (key) { + /* + * What about ALL_TG_TP? + */ + if (plist->all_tg_pt || + (strcmp(key->k_i_name, T10_PGR_INAME(cmd)) == 0)) { + + if (p_prout->action == PR_OUT_REGISTER && + key->k_key != reservation_key) { + /* + * The Initiator did not specify the + * existing key. Reservation conflict. + */ + return (STATUS_RESERVATION_CONFLICT); + } + /* + * Change existing key ? + */ + if (service_key) { + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT: change " + "old:%016lx = new:%016lx\n", + key->k_key, service_key); + + /* + * Overwrite (change) key + */ + key->k_key = service_key; + + } else { + /* + * Remove existing key + * NOTE: If we own the reservation then + * we must release it. + */ + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT: delete " + "old:%016lx = new:%016lx\n", + key->k_key, service_key); + + rsrv = spc_pr_rsrv_find(pgr, 0, + ti->s_i_name, ti->s_targ_base); + if (rsrv) { + spc_pr_rsrv_release( + cmd, pgr, rsrv); + } + spc_pr_key_free(pgr, key); + } + } + } else { + /* + * What about ALL_TG_TP? + */ + if (plist->all_tg_pt || + (strcmp(ti->s_i_name, T10_PGR_INAME(cmd)) == 0)) { + /* + * Process request from un-registered Initiator. + */ + if ((p_prout->action == PR_OUT_REGISTER) && + (reservation_key || service_key == 0)) { + /* + * Unregistered initiator is attempting + * to modify a key. + */ + return (STATUS_RESERVATION_CONFLICT); + } + + key = spc_pr_key_alloc(pgr, service_key, + ti->s_i_name, ti->s_targ_base); + if (key == NULL) { + /* pgr - define SCSI-3 error codes */ + cmd->c_lu->l_status = + KEY_ABORTED_COMMAND; + cmd->c_lu->l_asc = + SPC_ASC_MEMORY_OUT_OF; + cmd->c_lu->l_ascq = + SPC_ASCQ_RESERVATION_FAIL; + return (STATUS_CHECK); + } + } + } + lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); + } while (lu != NULL); + + /* + * Apply the last valid APTPL bit + * SPC-3, Revision 23 + * Section 5.6.4.1 Preserving persistent reservervations and + * registrations through power loss + */ + pgr->pgr_aptpl = plist->aptpl; + + return (STATUS_GOOD); +} + +/* + * []---- + * | spc_pr_out_reserve + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +/* ARGSUSED */ +static int +spc_pr_out_reserve(t10_cmd_t *cmd, void *data, size_t data_len) +{ + scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; + disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); + sbc_reserve_t *res = &p->d_sbc_reserve; + scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; + spc_pr_rsrv_t *rsrv; + scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; + uint64_t reservation_key; + uint64_t service_key; + int status; + + /* + * Do not allow an unregistered initiator to + * make a reservation. + */ + reservation_key = SCSI_READ64(plist->reservation_key); + service_key = SCSI_READ64(plist->service_key); + + queue_prt(mgmtq, Q_PR_NONIO, + "PGR%x LUN%d reserve reservation:%016lx, key:%016lx\n", + cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, + reservation_key, service_key); + + if (!spc_pr_key_find( + pgr, reservation_key, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd))) { + + queue_prt(mgmtq, Q_PR_ERRS, + "PGROUT: reserve service:%016lx not found\n", + reservation_key); + + return (STATUS_RESERVATION_CONFLICT); + } + + /* + * 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. + */ + if (rsrv = spc_pr_rsrv_find(pgr, 0, "", T10_PGR_TNAME(cmd))) { + if (strcmp(rsrv->r_i_name, T10_PGR_INAME(cmd)) != 0) { + + queue_prt(mgmtq, Q_PR_ERRS, + "PGROUT: reserve %s != %s:%s\n", rsrv->r_i_name, + T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)); + + return (STATUS_RESERVATION_CONFLICT); + } + } + + /* + * At this point there is either no reservation or the + * reservation is held by this Initiator. + */ + if (rsrv != NULL) { + + /* + * An Initiator cannot re-reserve. It must first + * release. But if its' type and scope match then + * return STATUS_GOOD. + */ + if (rsrv->r_type == p_prout->type && + rsrv->r_scope == p_prout->scope) { + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT reserve - transportID=%s\n" + "\tkey:%016lx i_name:%s scope:%d type:%d \n", + rsrv->r_transportID, rsrv->r_key, rsrv->r_i_name, + rsrv->r_scope, rsrv->r_type); + status = STATUS_GOOD; + } else { + queue_prt(mgmtq, Q_PR_ERRS, + "PGROUT reserve failed - transportID=%s\n" + "\tkey:%016lx i_name:%s scope:%d type:%d \n", + rsrv->r_transportID, rsrv->r_key, rsrv->r_i_name, + rsrv->r_scope, rsrv->r_type); + status = STATUS_RESERVATION_CONFLICT; + } + } else { + /* + * No reservation exists. Establish a new one. + */ + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT reserve - transportID=%s\n" + "\tkey:%016lx i_name:%s scope:%d type:%d \n", + T10_PGR_TNAME(cmd), reservation_key, T10_PGR_INAME(cmd), + p_prout->scope, p_prout->type); + + rsrv = spc_pr_rsrv_alloc(pgr, reservation_key, + T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd), + p_prout->scope, p_prout->type); + if (rsrv == NULL) { + cmd->c_lu->l_status = KEY_ABORTED_COMMAND; + cmd->c_lu->l_asc = SPC_ASC_MEMORY_OUT_OF; + cmd->c_lu->l_ascq = SPC_ASCQ_RESERVATION_FAIL; + status = STATUS_CHECK; + } else { + status = STATUS_GOOD; + } + } + + return (status); +} + +/* + * []---- + * | spc_pr_out_release + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +static int +spc_pr_out_release(t10_cmd_t *cmd, void *data, size_t data_len) +{ + scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; + disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); + sbc_reserve_t *res = &p->d_sbc_reserve; + scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; + spc_pr_rsrv_t *rsrv; + scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; + uint64_t reservation_key; + uint64_t service_key; + int status; + + /* + * Do not allow an unregistered initiator to + * make a reservation. + */ + reservation_key = SCSI_READ64(plist->reservation_key); + service_key = SCSI_READ64(plist->service_key); + + queue_prt(mgmtq, Q_PR_NONIO, + "PGR%x LUN%d release reservation:%016lx, key:%016lx\n", + cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, + reservation_key, service_key); + + if (!spc_pr_key_find( + pgr, reservation_key, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd))) { + + queue_prt(mgmtq, Q_PR_ERRS, + "PGROUT: release service:%016lx not found\n", + reservation_key); + + return (STATUS_RESERVATION_CONFLICT); + } else { + + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT: release service:%016lx\n", service_key); + } + + /* + * Releasing a non-existent reservation is allowed. + */ + if (!(rsrv = spc_pr_rsrv_find( + pgr, 0, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)))) { + + status = STATUS_GOOD; + + } else if (p_prout->scope != rsrv->r_scope || + p_prout->type != rsrv->r_type || + reservation_key != rsrv->r_key) { + queue_prt(mgmtq, Q_PR_ERRS, + "PGROUT release failed - transportID=%s\n" + "\tkey:%016lx i_name:%s scope:%d type:%d \n", + T10_PGR_TNAME(cmd), reservation_key, T10_PGR_INAME(cmd), + p_prout->scope, p_prout->type); + + /* + * Scope and key must match to release. + */ + cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST; + cmd->c_lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; + cmd->c_lu->l_ascq = SPC_ASCQ_RES_RELEASED; + status = STATUS_CHECK; + } else { + /* + * Now release the reservation. + */ + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT release - transportID=%s\n" + "\tkey:%016lx i_name:s scope:%d type:%d \n", + rsrv->r_transportID, rsrv->r_key, rsrv->r_i_name, + rsrv->r_scope, rsrv->r_type); + + spc_pr_rsrv_release(cmd, pgr, rsrv); + status = STATUS_GOOD; + } + + return (status); +} + +/* + * []---- + * | spc_pr_out_preempt + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +/* ARGSUSED */ +static int +spc_pr_out_preempt(t10_cmd_t *cmd, void *data, size_t data_len) +{ + scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; + disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); + sbc_reserve_t *res = &p->d_sbc_reserve; + scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; + scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; + uint64_t reservation_key; + uint64_t service_key; + spc_pr_key_t *key, *key_next; + spc_pr_rsrv_t *rsrv, *rsrv_next; + t10_lu_impl_t *lu; + int status = STATUS_GOOD; + + /* + * Get reservation values + */ + reservation_key = SCSI_READ64(plist->reservation_key); + service_key = SCSI_READ64(plist->service_key); + + queue_prt(mgmtq, Q_PR_NONIO, + "PGR%x LUN%d preempt reservation:%016lx, key:%016lx\n", + cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, + reservation_key, service_key); + + /* + * Service key (preempt key) must exist, and + * Initiator must be registered + */ + if (spc_pr_key_find(pgr, service_key, "", "") == NULL || + spc_pr_key_find(pgr, reservation_key, T10_PGR_INAME(cmd), "") == + NULL) { + + queue_prt(mgmtq, Q_PR_ERRS, + "PGROUT: preempt failed reservation:%016lx, key:%016lx\n", + reservation_key, service_key); + + return (STATUS_RESERVATION_CONFLICT); + } + + /* + * 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. + */ + for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; + key != (spc_pr_key_t *)&pgr->pgr_keylist; + key = (spc_pr_key_t *)key_next) { + + Boolean_t unit_attn; + + /* + * Get next pointer in case the key gets deallocated + */ + key_next = (spc_pr_key_t *)key->k_link.lnk_fwd; + + /* Skip non-matching keys */ + if (key->k_key != service_key) { + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT preempt key:%016lx != key:%016lx " + "i_name:%s transportID:%s\n", service_key, + key->k_key, key->k_i_name, key->k_transportID); + continue; + } + + /* + * Determine if UNIT ATTN needed + */ + unit_attn = strcmp(key->k_i_name, T10_PGR_INAME(cmd)); + + /* + * Remove the registration key + */ + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT preempt delete key:%016lx " + "i_name:%s transportID:%s\n", + key->k_key, key->k_i_name, key->k_transportID); + spc_pr_key_free(pgr, key); + + /* + * UNIT ATTN needed ? + * Do not set UNIT ATTN for calling Initiator + */ + if (unit_attn == False) + continue; + + /* + * Is this the preempt and abort? + */ + if (p_prout->action == PR_OUT_PREEMPT_ABORT) { + queue_message_set( + cmd->c_lu->l_common->l_from_transports, + Q_HIGH, msg_reset_lu, (void *)cmd->c_lu); + } + + /* + * Find associated I_T Nexuses + */ + (void) pthread_mutex_lock(&cmd->c_lu->l_common->l_common_mutex); + lu = avl_first(&cmd->c_lu->l_common->l_all_open); + do { + lu->l_status = KEY_UNIT_ATTENTION; + lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; + lu->l_ascq = SPC_ASCQ_RES_PREEMPTED; + lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); + } while (lu != NULL); + (void) pthread_mutex_unlock( + &cmd->c_lu->l_common->l_common_mutex); + } + + /* + * Re-establish our service key if we preempted it. + */ + if (!(key = spc_pr_key_find( + pgr, reservation_key, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)))) { + + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT: preempt - register:%016lx, i_name:%s:%s\n", + reservation_key, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)); + + key = spc_pr_key_alloc(pgr, reservation_key, + T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)); + if (key == NULL) { + cmd->c_lu->l_status = KEY_ABORTED_COMMAND; + cmd->c_lu->l_asc = SPC_ASC_MEMORY_OUT_OF; + cmd->c_lu->l_ascq = SPC_ASCQ_RESERVATION_FAIL; + return (STATUS_CHECK); + } + } + + /* + * Now look for a matching reservation to preempt. + */ + for (rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; + rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; + rsrv = (spc_pr_rsrv_t *)rsrv_next) { + + /* + * Get next pointer in case the reservation gets deallocated + */ + rsrv_next = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd; + + /* Skip non-matching keys */ + if (rsrv->r_key != service_key) { + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT preempt rsrv:%016lx != rsrv:%016lx" + "i_name:%s scope:%d type:%d \n", service_key, + rsrv->r_key, rsrv->r_i_name, + rsrv->r_scope, rsrv->r_type); + continue; + } + + /* + * 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. + */ + if (strcmp(rsrv->r_transportID, T10_PGR_TNAME(cmd))) { + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT preempt(-) rsrv:%016lx " + "i_name:%s scope:%d type:%d \n", + rsrv->r_key, rsrv->r_i_name, + rsrv->r_scope, rsrv->r_type); + + spc_pr_rsrv_free(pgr, rsrv); + continue; + } else { + /* + * We have a matching reservation so preempt it. + */ + rsrv->r_key = reservation_key; + rsrv->r_i_name = strdup(T10_PGR_INAME(cmd)); + rsrv->r_scope = p_prout->scope; + rsrv->r_type = p_prout->type; + + queue_prt(mgmtq, Q_PR_NONIO, + "PGROUT preempt(+) rsrv:%016lx " + "i_name:%s scope:%d type:%d \n", + rsrv->r_key, rsrv->r_i_name, + rsrv->r_scope, rsrv->r_type); + } + } + + return (status); +} + +/* + * []---- + * | spc_pr_out_clear + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +/* ARGSUSED */ +static int +spc_pr_out_clear(t10_cmd_t *cmd, void *data, size_t data_len) +{ + disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); + sbc_reserve_t *res = &p->d_sbc_reserve; + scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; + scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; + uint64_t reservation_key; + uint64_t service_key; + spc_pr_key_t *key; + t10_lu_impl_t *lu; + + /* + * Do not allow an unregistered initiator to attempting to + * clear the PGR. + */ + reservation_key = SCSI_READ64(plist->reservation_key); + service_key = SCSI_READ64(plist->service_key); + + queue_prt(mgmtq, Q_PR_NONIO, + "PGR%x LUN%d clear reservation:%016lx, key:%016lx\n", + cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, + reservation_key, service_key); + + if (!spc_pr_key_find(pgr, reservation_key, T10_PGR_INAME(cmd), "")) { + + queue_prt(mgmtq, Q_PR_ERRS, + "PGROUT: clear service:%016lx not found\n", + reservation_key); + + return (STATUS_RESERVATION_CONFLICT); + } + + /* + * We need to set UNIT ATTENTION for all registered initiators. + */ + for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; + key != (spc_pr_key_t *)&pgr->pgr_keylist; + key = (spc_pr_key_t *)key->k_link.lnk_fwd) { + + /* Do not set UNIT ATTN for calling Initiator */ + if (!(strcmp(key->k_i_name, T10_PGR_INAME(cmd)))) + continue; + /* + * At this point the only way to get in here is to be the owner + * of the reservation. + */ + (void) pthread_mutex_lock(&cmd->c_lu->l_common->l_common_mutex); + lu = avl_first(&cmd->c_lu->l_common->l_all_open); + do { + lu->l_status = KEY_UNIT_ATTENTION; + lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; + lu->l_ascq = SPC_ASCQ_RES_PREEMPTED; + lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); + } while (lu != NULL); + (void) pthread_mutex_unlock( + &cmd->c_lu->l_common->l_common_mutex); + } + + /* + * Now erase the reservation and registration info. + */ + spc_pr_erase(pgr); + + return (STATUS_GOOD); +} + +/* + * []---- + * | spc_pr_out_register_and_move + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +static int +spc_pr_out_register_and_move(t10_cmd_t *cmd, void *data, size_t data_len) +{ + return (STATUS_RESERVATION_CONFLICT); +} + +/* + * []---- + * | spc_pr_key_alloc - + * | Allocate a new registration key and add it to the key list. + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +static spc_pr_key_t * +spc_pr_key_alloc(scsi3_pgr_t *pgr, uint64_t service_key, char *i_name, + char *transportID) +{ + spc_pr_key_t *key = (spc_pr_key_t *) + memalign(sizeof (void *), sizeof (spc_pr_key_t)); + + if (key != NULL) { + key->k_key = service_key; + key->k_i_name = strdup(i_name); + key->k_transportID = strdup(transportID); + + insque(&key->k_link, pgr->pgr_keylist.lnk_bwd); + + pgr->pgr_numkeys++; + assert(pgr->pgr_numkeys > 0); + } + + return (key); +} + +/* + * []---- + * | spc_pr_initialize - + * | Initialize registration & reservervation queues + * []---- + */ +static void +spc_pr_initialize(scsi3_pgr_t *pgr) +{ + assert(pgr->pgr_numrsrv == 0); + assert(pgr->pgr_numkeys == 0); + pgr->pgr_rsrvlist.lnk_fwd = (key_link_t *)&pgr->pgr_rsrvlist.lnk_fwd; + + assert(pgr->pgr_rsrvlist.lnk_bwd == NULL); + pgr->pgr_rsrvlist.lnk_bwd = (key_link_t *)&pgr->pgr_rsrvlist.lnk_fwd; + + assert(pgr->pgr_keylist.lnk_fwd == NULL); + pgr->pgr_keylist.lnk_fwd = (key_link_t *)&pgr->pgr_keylist.lnk_fwd; + + assert(pgr->pgr_keylist.lnk_bwd == NULL); + pgr->pgr_keylist.lnk_bwd = (key_link_t *)&pgr->pgr_keylist.lnk_fwd; +} + +/* + * []---- + * | spc_pr_key_free - + * | Free a registration key + * []---- + */ +static void +spc_pr_key_free(scsi3_pgr_t *pgr, spc_pr_key_t *key) +{ + remque(&key->k_link); + free(key->k_i_name); + free(key->k_transportID); + free(key); + + pgr->pgr_numkeys--; + assert(pgr->pgr_numkeys >= 0); +} + +/* + * []---- + * | spc_pr_key_find - + * | Find a registration key based on the key, owner id and port id. + * []---- + */ +static spc_pr_key_t * +spc_pr_key_find(scsi3_pgr_t *pgr, uint64_t key, char *i_name, char *transportID) +{ + spc_pr_key_t *kp; + spc_pr_key_t *rval = NULL; + + for (kp = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; + kp != (spc_pr_key_t *)&pgr->pgr_keylist; + kp = (spc_pr_key_t *)kp->k_link.lnk_fwd) { + if ((key == 0 || kp->k_key == key) && + (strlen(i_name) == 0 || + (strcmp(kp->k_i_name, i_name) == 0)) && + (strlen(transportID) == 0 || + (strcmp(kp->k_transportID, transportID) == 0))) { + rval = kp; + break; + } + } + + return (rval); +} + + +/* + * []---- + * | spc_pr_rsrv_alloc - + * | Allocate a new reservation and add it to the rsrv list. + * []---- + */ +static spc_pr_rsrv_t * +spc_pr_rsrv_alloc(scsi3_pgr_t *pgr, uint64_t service_key, char *i_name, + char *transportID, uint8_t scope, uint8_t type) +{ + spc_pr_rsrv_t *rsrv = (spc_pr_rsrv_t *) + memalign(sizeof (void *), sizeof (spc_pr_rsrv_t)); + + if (rsrv != NULL) { + rsrv->r_key = service_key; + rsrv->r_i_name = strdup(i_name); + rsrv->r_transportID = strdup(transportID); + rsrv->r_scope = scope; + rsrv->r_type = type; + + insque(&rsrv->r_link, pgr->pgr_rsrvlist.lnk_bwd); + + pgr->pgr_numrsrv++; + assert(pgr->pgr_numrsrv > 0); + } + + return (rsrv); +} + + +/* + * []---- + * | spc_pr_rsrv_free - + * | Free a reservation. + * []---- + */ +static void +spc_pr_rsrv_free(scsi3_pgr_t *pgr, spc_pr_rsrv_t *rsrv) +{ + remque(&rsrv->r_link); + free(rsrv->r_i_name); + free(rsrv->r_transportID); + free(rsrv); + + pgr->pgr_numrsrv--; + assert(pgr->pgr_numrsrv >= 0); +} + +/* + * []---- + * | spc_pr_rsrv_find - + * | Find a reservation based on the key, owner id and port id. + * []---- + */ +static spc_pr_rsrv_t * +spc_pr_rsrv_find(scsi3_pgr_t *pgr, uint64_t key, char *i_name, + char *transportID) +{ + spc_pr_rsrv_t *rp, *rval = NULL; + + for (rp = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; + rp != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; + rp = (spc_pr_rsrv_t *)rp->r_link.lnk_fwd) { + if ((key == 0 || rp->r_key == key) && + (strlen(i_name) == 0 || + (strcmp(rp->r_i_name, i_name) == 0)) && + (strlen(transportID) == 0 || + (strcmp(rp->r_transportID, transportID) == 0))) { + rval = rp; + break; + } + } + + return (rval); +} + +/* + * []---- + * | spc_pr_erase - + * | Find specified key / reservation and erease it + * []---- + */ +/* + */ +static void +spc_pr_erase(scsi3_pgr_t *pgr) +{ + spc_pr_key_t *key; + spc_pr_rsrv_t *rsrv; + + while ((key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd) != + (spc_pr_key_t *)&pgr->pgr_keylist) { + spc_pr_key_free(pgr, key); + } + + assert(pgr->pgr_numkeys == 0); + + while ((rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd) != + (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist) { + spc_pr_rsrv_free(pgr, rsrv); + } + + assert(pgr->pgr_numrsrv == 0); + + pgr->pgr_generation = 0; + pgr->pgr_aptpl = 0; +} + +/* + * []---- + * | spc_pr_rsrv_release - + * | Release the reservation the perform any other required clearing actions. + * | Refer to SPC-3, Section 6.1, Tables ?? and ?? + * []---- + */ +static void +spc_pr_rsrv_release(t10_cmd_t *cmd, scsi3_pgr_t *pgr, spc_pr_rsrv_t *rsrv) +{ + t10_lu_impl_t *lu; + spc_pr_key_t *key; + + /* + * For Registrants-Only mode set UNIT ATTN. + */ + if (rsrv->r_type == PGR_TYPE_WR_EX_RO || + rsrv->r_type == PGR_TYPE_EX_AC_RO) { + + for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; + key != (spc_pr_key_t *)&pgr->pgr_keylist; + key = (spc_pr_key_t *)key->k_link.lnk_fwd) { + + /* + * No UNIT ATTN for the requesting Initiator. + */ + if (!(strcmp(key->k_i_name, T10_PGR_INAME(cmd)))) + continue; + + /* + * Find associated I_T Nexuses + */ + (void) pthread_mutex_lock( + &cmd->c_lu->l_common->l_common_mutex); + lu = avl_first(&cmd->c_lu->l_common->l_all_open); + do { + lu->l_status = KEY_UNIT_ATTENTION; + lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; + lu->l_ascq = SPC_ASCQ_RES_RELEASED; + lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, + lu); + } while (lu != NULL); + (void) pthread_mutex_unlock( + &cmd->c_lu->l_common->l_common_mutex); + } + } + + /* + * Remove the reservation. + */ + spc_pr_rsrv_free(pgr, rsrv); +} + +/* + * []---- + * | spc_pr_read - + * | Read in pgr keys and reservations for this device from backend storage. + * | At least the local pgr write lock must be held. + * []---- + */ +void +spc_pr_read(t10_cmd_t *cmd) +{ + disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); + sbc_reserve_t *res = &p->d_sbc_reserve; + scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; + spc_pr_key_t *key; + spc_pr_rsrv_t *rsrv; + spc_pr_diskkey_t *klist; + spc_pr_diskrsrv_t *rlist; + spc_pr_persist_disk_t *buf = NULL; + t10_lu_impl_t *lu; + int i, pfd; + Boolean_t status = False; + char path[MAXPATHLEN]; + + /* + * Open the PERSISTANCE file specification if one exists + */ + (void) snprintf(path, MAXPATHLEN, "%s/%s/%s%d", + target_basedir, cmd->c_lu->l_targ->s_targ_base, + PERSISTANCEBASE, cmd->c_lu->l_common->l_num); + if ((pfd = open(path, O_RDONLY)) >= 0) { + struct stat pstat; + if ((fstat(pfd, &pstat)) == 0) + if (pstat.st_size > 0) + if (buf = malloc(pstat.st_size)) + if (read(pfd, buf, pstat.st_size) == + pstat.st_size) + status = True; + } + + /* + * Clean up on no persistence file found + */ + if (status == False) { + if (pfd >= 0) + close(pfd); + if (buf) + free(buf); + return; + } + + /* + * If this is the first time using the persistance data, + * initialize the reservation and resource key queues + */ + if (pgr->pgr_rsrvlist.lnk_fwd == NULL) { + (void) spc_pr_initialize(pgr); + } + + /* + * Perform some vailidation on what we are looking at + */ + assert(buf->magic == PGRMAGIC); + assert(buf->revision == SPC_PGR_PERSIST_DATA_REVISION); + + /* + * Get the PGR keys + */ + klist = (spc_pr_diskkey_t *)&buf->keylist[0]; + for (i = 0; i < buf->numkeys; i++) { + assert(klist[i].rectype == PGRDISKKEY); + + /* + * Was the key previously read, if not restore it + */ + key = spc_pr_key_find(pgr, 0, T10_PGR_INAME(cmd), + T10_PGR_TNAME(cmd)); + if (key == NULL) + key = spc_pr_key_alloc(pgr, klist[i].key, + klist[i].i_name, klist[i].transportID); + assert(key); + } + + /* + * Get the PGR reservations + */ + rlist = (spc_pr_diskrsrv_t *)&buf->keylist[buf->numkeys]; + for (i = 0; i < buf->numrsrv; i++) { + assert(rlist[i].rectype == PGRDISKRSRV); + + /* + * Was the reservation previously read, if not restore it + */ + rsrv = spc_pr_rsrv_find(pgr, 0, T10_PGR_INAME(cmd), + T10_PGR_TNAME(cmd)); + if (rsrv == NULL) + rsrv = spc_pr_rsrv_alloc(pgr, rlist[i].key, + rlist[i].i_name, rlist[i].transportID, + rlist[i].scope, rlist[i].type); + assert(rsrv); + } + + /* + * If there was data then set the reservation type. + */ + if (pgr->pgr_numkeys > 0 || pgr->pgr_numrsrv > 0) { + res->res_type = RT_PGR; + pgr->pgr_generation = buf->generation; + + /* + * Set the command dispatcher according to the reservation type + */ + (void) pthread_mutex_lock(&cmd->c_lu->l_common->l_common_mutex); + lu = avl_first(&cmd->c_lu->l_common->l_all_open); + do { + lu->l_cmd = sbc_cmd_reserved; + lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); + } while (lu != NULL); + (void) pthread_mutex_unlock( + &cmd->c_lu->l_common->l_common_mutex); + } + + free(buf); +} + +/* + * []---- + * | spc_pr_write - + * | Write PGR keys and reservations for this device to backend storage. + * | At least the local pgr write lock must be held. + * []---- + */ +Boolean_t +spc_pr_write(t10_cmd_t *cmd) +{ + disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); + sbc_reserve_t *res = &p->d_sbc_reserve; + scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; + spc_pr_key_t *key; + spc_pr_rsrv_t *rsrv; + spc_pr_diskkey_t *klist; + spc_pr_diskrsrv_t *rlist; + spc_pr_persist_disk_t *buf; + ssize_t length, bufsize; + int i, pfd = -1; + char path[MAXPATHLEN]; + Boolean_t status = True; + + /* + * 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. + */ + bufsize = sizeof (spc_pr_persist_disk_t) + + (pgr->pgr_numkeys - 1) * sizeof (spc_pr_diskkey_t) + + pgr->pgr_numrsrv * sizeof (spc_pr_diskrsrv_t); + bufsize = roundup(bufsize, 512); + if ((buf = memalign(sizeof (void *), bufsize)) == NULL) + return (False); + else + bzero(buf, bufsize); + + /* + * Build header. + */ + buf->magic = PGRMAGIC; + buf->revision = SPC_PGR_PERSIST_DATA_REVISION; + buf->generation = pgr->pgr_generation; + buf->numkeys = pgr->pgr_numkeys; + buf->numrsrv = pgr->pgr_numrsrv; + + /* + * Copy the keys. + */ + klist = buf->keylist; + for (i = 0, key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; + key != (spc_pr_key_t *)&pgr->pgr_keylist && i < pgr->pgr_numkeys; + key = (spc_pr_key_t *)key->k_link.lnk_fwd, i++) { + + klist[i].rectype = PGRDISKKEY; + klist[i].key = key->k_key; + strncpy(klist[i].i_name, key->k_i_name, + sizeof (klist[i].i_name)); + strncpy(klist[i].transportID, key->k_transportID, + sizeof (klist[i].transportID)); + } + + /* + * Copy the reservations. + */ + rlist = (spc_pr_diskrsrv_t *)&buf->keylist[pgr->pgr_numkeys]; + for (i = 0, rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; + rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist && + i < pgr->pgr_numrsrv; + rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd, i++) { + + rlist[i].rectype = PGRDISKRSRV; + rlist[i].key = rsrv->r_key; + rlist[i].scope = rsrv->r_scope; + rlist[i].type = rsrv->r_type; + strncpy(rlist[i].i_name, rsrv->r_i_name, + sizeof (rlist[i].i_name)); + strncpy(rlist[i].transportID, rsrv->r_transportID, + sizeof (rlist[i].transportID)); + } + + /* + * Open/create the PERSISTANCE file specification + */ + (void) snprintf(path, MAXPATHLEN, "%s/%s/%s%d", + target_basedir, cmd->c_lu->l_targ->s_targ_base, + PERSISTANCEBASE, cmd->c_lu->l_common->l_num); + if ((pfd = open(path, O_WRONLY|O_CREAT, 0600)) >= 0) { + length = write(pfd, buf, bufsize); + close(pfd); + } else { + if ((pfd < 0) || (length != bufsize)) + status = False; + } + + /* + * Free allocated buffer + */ + free(buf); + return (status); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h Thu Sep 13 15:17:59 2007 -0700 @@ -0,0 +1,163 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _T10_SPC_PR_H +#define _T10_SPC_PR_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SPC-3 Persistent Reservation specific structures and defines + */ + +/* + * Key Linked Lists + */ +typedef struct key_link { + union { + uint64_t align; + struct { + struct key_link *_lnk_fwd; /* Forward element */ + struct key_link *_lnk_bwd; /* Backward element */ + } key_ptr; + } key_link; +} key_link_t; +#define lnk_fwd key_link.key_ptr._lnk_fwd +#define lnk_bwd key_link.key_ptr._lnk_bwd +#define insque(a, b) \ + ((key_link_t *)(a))->lnk_fwd = (key_link_t *)(b); \ + ((key_link_t *)(a))->lnk_bwd = ((key_link_t *)(b))->lnk_bwd; \ + ((key_link_t *)(b))->lnk_bwd = (key_link_t *)(a); \ + ((key_link_t *)(a))->lnk_bwd->lnk_fwd = (key_link_t *)(a); + +#define remque(A) \ + ((key_link_t *)(A))->lnk_bwd->lnk_fwd = ((key_link_t *)(A))->lnk_fwd; \ + ((key_link_t *)(A))->lnk_fwd->lnk_bwd = ((key_link_t *)(A))->lnk_bwd; + +/* + * Reservation Types (res_type). + */ +typedef enum { + RT_NONE = 0, /* None */ + RT_PGR /* SCSI-3 Persistent Reservation */ +} spc_reserve_types; + +/* + * Persistent reservation data. + */ +typedef struct spc_pr_key { + key_link_t k_link; /* Key linked list */ + uint64_t k_key; /* registration key */ + char *k_i_name; /* initiator name */ + char *k_transportID; /* transport ID */ +} spc_pr_key_t; + +typedef struct spc_pr_rsrv { + key_link_t r_link; /* Key linked list */ + uint64_t r_key; /* reservation key */ + char *r_i_name; /* initiator name */ + char *r_transportID; /* transport ID */ + uint8_t r_scope; /* reservation scope */ + uint8_t r_type; /* reservation type */ +} spc_pr_rsrv_t; + +/* + * Persistent Reservation data + */ +typedef struct scsi3_pgr { + uint32_t pgr_generation; /* PGR PRgeneration value */ + uint16_t pgr_unused; + uint16_t pgr_bits : 15, + pgr_aptpl : 1; /* persistence data exists */ + int32_t pgr_numkeys; /* # entries in key list */ + int32_t pgr_numrsrv; /* # entries in rsrv list */ + key_link_t pgr_keylist; /* Registration key list */ + key_link_t pgr_rsrvlist; /* reservation list */ +} scsi3_pgr_t; + +typedef struct sbc_reserve { + spc_reserve_types res_type; /* standard or pr active */ + pthread_rwlock_t res_rwlock; /* Lock for coordination */ + scsi3_pgr_t res_scsi_3_pgr; /* SCSI-3 PGR */ +} sbc_reserve_t; + +/* + * On-disk PGR data. + * + * NOTE: The following three structures should be rounded up to 512 bytes each + * to prevent potential problems with on-disk data skew + */ +typedef struct spc_pr_diskkey { + uint64_t key; /* registration key (8) */ + uint32_t rectype; /* record type (4) */ + char i_name[224]; /* initiator name (224) */ + char filler1[20]; /* filler to 256 bytes */ + char transportID[228]; /* transport ID (228) */ + char filler2[28]; /* filler to 512 bytes */ +} spc_pr_diskkey_t; + +typedef struct spc_pr_diskrsrv { + uint64_t key; /* reservation key (8) */ + uint32_t rectype; /* record type (4) */ + uint8_t scope; /* reservation scope (1) */ + uint8_t type; /* reservation type (1) */ + char i_name[224]; /* initiator name (224) */ + char filler1[18]; /* filler to 256 bytes */ + char transportID[228]; /* Transport ID (228) */ + char filler2[28]; /* filler to 512 bytes */ +} spc_pr_diskrsrv_t; + +typedef struct spc_pr_persist_disk { + uint64_t magic; /* magic number (8) */ + uint32_t revision; /* header format revision (4) */ + uint32_t generation; /* pgr generation count (4) */ + int32_t numkeys; /* # items in key list (4) */ + int32_t numrsrv; /* # items in rsrv list (4) */ + char filler[488]; /* 8+4+4+4+4 */ + +/* + * After the header the data is laid out as follows: + * spc_pr_diskkey_t keylist[]; + * spc_pr_diskrsrv_t rsrvlist[]; + */ + spc_pr_diskkey_t keylist[1]; +} spc_pr_persist_disk_t; + + +#define SPC_PGR_PERSIST_DATA_REVISION 0x01 /* REVISON = 1 */ +#define PGRMAGIC 0x5047524D41474943LL /* "PGRMAGIC" */ +#define PGRDISKKEY 0x5047526B /* "PGRk" */ +#define PGRDISKRSRV 0x50475272 /* "PGRr" */ + +#ifdef __cplusplus +} +#endif + +#endif /* _T10_SPC_PR_H */
--- a/usr/src/cmd/iscsi/iscsitgtd/target.h Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/target.h Thu Sep 13 15:17:59 2007 -0700 @@ -76,8 +76,16 @@ #define PARAMBASE "params." #define LUNBASE "lun." #define OSDBASE "osd_root." +#define PERSISTANCEBASE "pgr." +#define ISCSI_TARGET_ALIAS "TargetAlias" -#define ISCSI_TARGET_ALIAS "TargetAlias" +/* + * Base file name for persistent reservation data (PR). The format used is pr. + * This name is used both to build the PR name and when searching the target + * directory for persistent reservation data. Don't change these names unless + * the upgrade path has been thought about. + */ +#define PRBASE "persistent_reservations" /* * The IQN names that are created use libuuid + the local target name @@ -201,7 +209,8 @@ extern Boolean_t enforce_strict_guid, thin_provisioning, disable_tpgs, - dbg_timestamps; + dbg_timestamps, + pgr_persist; extern pthread_mutex_t targ_config_mutex; extern umem_cache_t *iscsi_cmd_cache, *t10_cmd_cache,
--- a/usr/src/cmd/iscsi/iscsitgtd/util_queue.c Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/util_queue.c Thu Sep 13 15:17:59 2007 -0700 @@ -196,8 +196,8 @@ queue_walker_free(target_queue_t *q, Boolean_t (*func)(msg_t *m, void *v), void *v1) { - msg_t *m, /* current working message */ - *n; /* next message */ + msg_t *m; /* current working message */ + msg_t *n; /* next message */ (void) pthread_mutex_lock(&q->q_mutex); m = q->q_head; @@ -234,8 +234,8 @@ void queue_reset(target_queue_t *q) { - msg_t *m, - *n; + msg_t *m; + msg_t *n; (void) pthread_mutex_lock(&q->q_mutex); m = q->q_head; @@ -301,8 +301,8 @@ void queue_free(target_queue_t *q, void (*free_func)(msg_t *)) { - msg_t *m, - *n; + msg_t *m; + msg_t *n; (void) pthread_mutex_lock(&q->q_mutex); m = q->q_head; @@ -343,8 +343,8 @@ { int len; char *m; - hrtime_t h = gethrtime(), - delta; + hrtime_t h = gethrtime(); + hrtime_t delta; static hrtime_t last_h = 0; (void) pthread_mutex_lock(&q_mutex);
--- a/usr/src/lib/libiscsitgt/common/iscsitgt_impl.h Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/lib/libiscsitgt/common/iscsitgt_impl.h Thu Sep 13 15:17:59 2007 -0700 @@ -145,6 +145,7 @@ #define XML_ELEMENT_VALIDATE "validate" #define XML_ELEMENT_MORESPACE "more-space-required" #define XML_VALUE_TRUE "true" +#define XML_ELEMENT_PGR_PERSIST "PGR-persist" typedef enum { NodeFree,
--- a/usr/src/pkgdefs/SUNWhea/prototype_com Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/pkgdefs/SUNWhea/prototype_com Thu Sep 13 15:17:59 2007 -0700 @@ -1141,6 +1141,7 @@ f none usr/include/sys/scsi/generic/inquiry.h 644 root bin f none usr/include/sys/scsi/generic/message.h 644 root bin f none usr/include/sys/scsi/generic/mode.h 644 root bin +f none usr/include/sys/scsi/generic/persist.h 644 root bin f none usr/include/sys/scsi/generic/sense.h 644 root bin f none usr/include/sys/scsi/generic/status.h 644 root bin d none usr/include/sys/scsi/impl 755 root bin
--- a/usr/src/uts/common/sys/Makefile Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/uts/common/sys/Makefile Thu Sep 13 15:17:59 2007 -0700 @@ -788,6 +788,7 @@ inquiry.h \ message.h \ mode.h \ + persist.h \ sense.h \ status.h
--- a/usr/src/uts/common/sys/scsi/generic/commands.h Thu Sep 13 13:50:11 2007 -0700 +++ b/usr/src/uts/common/sys/scsi/generic/commands.h Thu Sep 13 15:17:59 2007 -0700 @@ -332,6 +332,11 @@ #define SCMD_GROUP5 0xA0 #define SCMD_REPORT_LUNS 0xA0 #define SCMD_REPORT_TARGET_PORT_GROUPS 0xA3 +#define SCMD_SET_DEVICE 0xA4 +#define SCMD_SET_DEVICE_IDENTIFIER 0x06 +#define SCMD_SET_PRIORITY 0x0e +#define SCMD_SET_TARGET_PORT_GROUPS 0x0a +#define SCMD_SET_TIMESTAMP 0x0f #define SCMD_READ_G5 0xA8 #define SCMD_WRITE_G5 0xAA #define SCMD_READ_MEDIA_SERIAL 0xAB
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/sys/scsi/generic/persist.h Thu Sep 13 15:17:59 2007 -0700 @@ -0,0 +1,404 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_SCSI_GENERIC_PERSIST_H +#define _SYS_SCSI_GENERIC_PERSIST_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SCSI Persistence Data + * + * Format of data returned as a result of PERSISTENCE RESERVER { IN | OUT } + */ + +/* + * SPC-3 revision 23, Section 6.11.1, Table 102 + * Persistent Reservations + * Persistent Reserve In service actions + */ +#define PR_IN_READ_KEYS 0x0 /* Read all registered reservation keys */ +#define PR_IN_READ_RESERVATION 0x1 /* Reads th persistent reservations */ +#define PR_IN_REPORT_CAPABILITIES 0x2 /* Returns capability information */ +#define PR_IN_READ_FULL_STATUS 0x3 /* Reads complete information about all */ + /* registrations and the persistent */ + /* reservations, if any */ +/* + * SPC-3 revision 23, Section 6.11.3.3, Table 106 + * Persistent reservation scope codes + */ +#define PR_LU_SCOPE 0x0 /* Persistent reservation applies to */ + /* full logical unit */ +/* + * SPC-3 revision 23, Section 6.11.3.4, Table 107 + * Persistent Reservations + * Persistent reservation type codes + */ +#define PGR_TYPE_WR_EX 0x1 /* Write Exclusive */ +#define PGR_TYPE_EX_AC 0x3 /* Exclusive Access */ +#define PGR_TYPE_WR_EX_RO 0x5 /* Write Exclusive, Registrants Only */ +#define PGR_TYPE_EX_AC_RO 0x6 /* Exclusive Access, Registrants Only */ +#define PGR_TYPE_WR_EX_AR 0x7 /* Write Exclusive, All Registrants */ +#define PGR_TYPE_EX_AC_AR 0x8 /* Exclusive Access, All Registrants */ + +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.11.5 PERSISTENCE RESERVE IN + * Table 111 - full status descriptor format + */ +/* Table 289 - iSCSI Initiator Device TransportID format */ + +#define iSCSI_PROTOCOL_ID 0x5 /* Table 262 - iSCSI Protocol ID */ +#define WW_UID_DEVICE_NAME 0x0 /* Table 288 - iSCSI Transport IDs */ + + +#if defined(_BIT_FIELDS_LTOH) +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.11.1 PERSISTENCE RESERVE IN + * Table 101 - PERSISTENCE RESERVE IN command + */ +typedef struct scsi_cdb_prin { + uint8_t cmd; + uint8_t action : 5, + resbits : 3; + uint8_t resbytes[5]; + uint8_t alloc_len[2]; + uint8_t control; +} scsi_cdb_prin_t; + +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.11.2 PERSISTENCE RESERVE IN + * Table 103/104/105 - parameter data for READS KEYS + */ +typedef struct scsi_prin_rsrvdesc { + uint8_t reservation_key[8]; + uint8_t obsolete1[4]; + uint8_t resbytes; + uint8_t type : 4, + scope : 4; + uint8_t obsolete2[2]; +} scsi_prin_rsrvdesc_t; +typedef struct scsi_prin_readrsrv { + uint8_t PRgeneration[4]; + uint8_t add_len[4]; + union { + uint64_t service_key[1]; + scsi_prin_rsrvdesc_t res_key_list[1]; + } key_list; +} scsi_prin_readrsrv_t; + +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.11.4 PERSISTENCE RESERVE IN + * Table 108 - parameter data for REPORT CAPABILTIES + */ +typedef struct scsi_per_res_type { + uint8_t resbits1 : 1, + wr_ex : 1, + resbits2 : 1, + ex_ac : 1, + resbits3 : 1, + wr_ex_ro : 1, + ex_ac_ro : 1, + wr_ex_ar : 1; + uint8_t ex_ac_ar : 1, + resbits4 : 7; +} scsi_per_res_type_t; +typedef struct scsi_prin_rpt_cap { + uint8_t length[2]; + uint8_t ptpl_c : 1, + resbits1 : 1, + atp_c : 1, + sip_c : 1, + crh : 1, + resbits2 : 3; + uint8_t ptpl_a : 1, + resbits3 : 6, + tmv : 1; + scsi_per_res_type_t pr_type; + uint8_t resbytes[2]; +} scsi_prin_rpt_cap_t; + +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.11.5 PERSISTENCE RESERVE IN + * Table 110/111 - parameter data for READ FULL STATUS + * Table 281 - TransportId format + */ +typedef struct scsi_transport_id { + uint8_t protocol_id : 4, + resbits : 2, + format_code : 2; + uint8_t add_len[2]; + char iscsi_name[1]; +} scsi_transport_id_t; +typedef struct scsi_prin_status_t { + uint8_t reservation_key[8]; + uint8_t resbytes1[4]; + uint8_t r_holder : 1, + all_tg_pt : 1, + resbits : 6; + uint8_t type : 4, + scope : 4; + uint8_t resbytes2[4]; + uint8_t rel_tgt_port_id[2]; + uint8_t add_len[4]; + scsi_transport_id_t trans_id; +} scsi_prin_status_t; +typedef struct scsi_prin_full_status { + uint8_t PRgeneration[4]; + uint8_t add_len[4]; + scsi_prin_status_t full_desc[1]; +} scsi_prin_full_status_t; + +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.12.1 PERSISTENCE RESERVE OUT + * Table 112 - PERSISTENCE RESERVE OUT command + */ +typedef struct scsi_cdb_prout { + uint8_t cmd; + uint8_t action : 5, + resbits : 3; + uint8_t type : 4, + scope : 4; + uint8_t resbytes[2]; + uint8_t param_len[4]; + uint8_t control; +} scsi_cdb_prout_t; + +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.12.3 PERSISTENCE RESERVE OUT + * Table 114 - PERSISTENCE RESERVE OUT parameter list + */ +typedef struct scsi_prout_plist { + uint8_t reservation_key[8]; + uint8_t service_key[8]; + uint8_t obsolete1[4]; + uint8_t aptpl : 1, + resbits1 : 1, + all_tg_pt : 1, + spec_i_pt : 1, + resbits2 : 4; + uint8_t resbytes1; + uint8_t obsolete2[2]; + uint8_t apd[1]; +} scsi_prout_plist_t; + +#elif defined(_BIT_FIELDS_HTOL) +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.11.1 PERSISTENCE RESERVE IN + * Table 101 - PERSISTENCE RESERVE IN command + */ +typedef struct scsi_cdb_prin { + uint8_t cmd; + uint8_t resbits : 3, + action : 5; + uint8_t resbytes[5]; + uint8_t alloc_len[2]; + uint8_t control; +} scsi_cdb_prin_t; + +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.11.2 PERSISTENCE RESERVE IN + * Table 103/104/105 - parameter data for READS KEYS + */ +typedef struct scsi_prin_rsrvdesc { + uint8_t reservation_key[8]; + uint8_t obsolete1[4]; + uint8_t resbytes; + uint8_t scope : 4, + type : 4; + uint8_t obsolete2[2]; +} scsi_prin_rsrvdesc_t; +typedef struct scsi_prin_readrsrv { + uint8_t PRgeneration[4]; + uint8_t add_len[4]; + union { + uint64_t service_key[1]; + scsi_prin_rsrvdesc_t res_key_list[1]; + } key_list; +} scsi_prin_readrsrv_t; + +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.11.4 PERSISTENCE RESERVE IN + * Table 108 - parameter data for REPORT CAPABILTIES + */ +typedef struct scsi_per_res_type { + uint8_t wr_ex_ar : 1, + ex_ac_ro : 1, + wr_ex_ro : 1, + resbits3 : 1, + ex_ac : 1, + resbits2 : 1, + wr_ex : 1, + resbits1 : 1; + uint8_t resbits4 : 7, + ex_ac_ar : 1; +} scsi_per_res_type_t; +typedef struct scsi_prin_rpt_cap { + uint8_t length[2]; + uint8_t resbits2 : 3, + crh : 1, + sip_c : 1, + atp_c : 1, + resbits1 : 1, + ptpl_c : 1; + uint8_t tmv : 1, + resbits3 : 6, + ptpl_a : 1; + scsi_per_res_type_t pr_type; + uint8_t resbytes[2]; +} scsi_prin_rpt_cap_t; + +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.11.5 PERSISTENCE RESERVE IN + * Table 110/111 - parameter data for READ FULL STATUS + * Table 281 - TransportId format + */ +typedef struct scsi_transport_id { + uint8_t format_code : 2, + resbits : 2, + protocol_id : 4; + uint8_t add_len[2]; + char iscsi_name[1]; +} scsi_transport_id_t; +typedef struct scsi_prin_status_t { + uint8_t reservation_key[8]; + uint8_t resbytes1[4]; + uint8_t resbits : 6, + all_tg_pt : 1, + r_holder : 1; + uint8_t scope : 4, + type : 4; + uint8_t resbytes2[4]; + uint8_t rel_tgt_port_id[2]; + uint8_t add_len[4]; + scsi_transport_id_t trans_id; +} scsi_prin_status_t; +typedef struct scsi_prin_full_status { + uint8_t PRgeneration[4]; + uint8_t add_len[4]; + scsi_prin_status_t full_desc[1]; +} scsi_prin_full_status_t; + +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.12.1 PERSISTENCE RESERVE OUT + * Table 112 - PERSISTENCE RESERVE OUT command + */ +typedef struct scsi_cdb_prout { + uint8_t cmd; + uint8_t resbits : 3, + action : 5; + uint8_t scope : 4, + type : 4; + uint8_t resbytes[2]; + uint8_t param_len[4]; + uint8_t control; +} scsi_cdb_prout_t; + +/* + * Information obtained from: + * SPC-3, Revision 23 + * Section 6.12.3 PERSISTENCE RESERVE OUT + * Table 114 - PERSISTENCE RESERVE OUT parameter list + */ +typedef struct scsi_prout_plist { + uint8_t reservation_key[8]; + uint8_t service_key[8]; + uint8_t obsolete1[4]; + uint8_t resbits1 : 4, + spec_i_pt : 1, + all_tg_pt : 1, + resbits2 : 1, + aptpl : 1; + uint8_t resbytes1; + uint8_t obsolete2[2]; + uint8_t apd[1]; +} scsi_prout_plist_t; + +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif /* _BIT_FIELDS_LTOH */ + + +/* + * SPC-3 revision 23, Section 6.12.2, Table 113 + * Persistent Reservations + * Persistent Reserve Out service action codes + */ +#define PR_OUT_REGISTER 0x0 /* Register/unregister a reservation */ + /* key with the device server */ +#define PR_OUT_RESERVE 0x1 /* Create a persistent reservation */ + /* having a specified SCOPE & TYPE */ +#define PR_OUT_RELEASE 0x2 /* Release the selected persistent */ + /* reservation */ +#define PR_OUT_CLEAR 0x3 /* Clears all reservation keys and */ + /* all persistent reservations */ +#define PR_OUT_PREEMPT 0x4 /* Preempts persistent reservations */ + /* and/or removes reservations */ +#define PR_OUT_PREEMPT_ABORT 0x5 /* Preempts persistent reservations */ + /* and/or removes reservations, and */ + /* aborts all tasks for all preempted */ + /* I_T nexuses */ +#define PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY 0x06 + /* Register a reservation key with */ + /* the device server, or unregister a */ + /* reservation key */ +#define PR_OUT_REGISTER_MOVE 0x7 /* Register a reservation key for */ + /* another I_T nexus with the device */ + /* server and move a persistent */ + /* reservation to the I_T nexus */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SCSI_GENERIC_PERSIST_H */