/* warning: addr must be aligned */ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL, hwaddr addr, MemTxAttrs attrs, MemTxResult *result, enum device_endian endian) { uint8_t *ptr; uint64_t val; MemoryRegion *mr; hwaddr l = 2; hwaddr addr1; MemTxResult r; bool release_lock = false; RCU_READ_LOCK(); mr = TRANSLATE(addr, &addr1, &l, false); if (l < 2 || !IS_DIRECT(mr, false)) { release_lock |= prepare_mmio_access(mr); /* I/O case */ r = memory_region_dispatch_read(mr, addr1, &val, 2, attrs); #if defined(TARGET_WORDS_BIGENDIAN) if (endian == DEVICE_LITTLE_ENDIAN) { val = bswap16(val); } #else if (endian == DEVICE_BIG_ENDIAN) { val = bswap16(val); } #endif } else { /* RAM case */ ptr = MAP_RAM(mr, addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: val = lduw_le_p(ptr); break; case DEVICE_BIG_ENDIAN: val = lduw_be_p(ptr); break; default: val = lduw_p(ptr); break; } r = MEMTX_OK; } if (result) { *result = r; } if (release_lock) { qemu_mutex_unlock_iothread(); } RCU_READ_UNLOCK(); return val; }
static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, const uint8_t *param, int sz) { int rq_servact = cdb[1]; int rq_scope = cdb[2] >> 4; int rq_type = cdb[2] & 0xf; struct prout_param_descriptor paramp; char transportids[PR_HELPER_DATA_SIZE]; int r; if (sz < PR_OUT_FIXED_PARAM_SIZE) { /* Illegal request, Parameter list length error. This isn't fatal; * we have read the data, send an error without closing the socket. */ scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM_LEN)); return CHECK_CONDITION; } switch (rq_servact) { case MPATH_PROUT_REG_SA: case MPATH_PROUT_RES_SA: case MPATH_PROUT_REL_SA: case MPATH_PROUT_CLEAR_SA: case MPATH_PROUT_PREE_SA: case MPATH_PROUT_PREE_AB_SA: case MPATH_PROUT_REG_IGN_SA: break; case MPATH_PROUT_REG_MOV_SA: /* Not supported by struct prout_param_descriptor. */ default: /* Cannot parse any other input. */ scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD)); return CHECK_CONDITION; } /* Convert input data, especially transport IDs, to the structs * used by libmpathpersist (which, of course, will immediately * do the opposite). */ memset(¶mp, 0, sizeof(paramp)); memcpy(¶mp.key, ¶m[0], 8); memcpy(¶mp.sa_key, ¶m[8], 8); paramp.sa_flags = param[20]; if (sz > PR_OUT_FIXED_PARAM_SIZE) { size_t transportid_len; int i, j; if (sz < PR_OUT_FIXED_PARAM_SIZE + 4) { scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM_LEN)); return CHECK_CONDITION; } transportid_len = ldl_be_p(¶m[24]) + PR_OUT_FIXED_PARAM_SIZE + 4; if (transportid_len > sz) { scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM)); return CHECK_CONDITION; } for (i = PR_OUT_FIXED_PARAM_SIZE + 4, j = 0; i < transportid_len; ) { struct transportid *id = (struct transportid *) &transportids[j]; int len; id->format_code = param[i] & 0xc0; id->protocol_id = param[i] & 0x0f; switch (param[i] & 0xcf) { case 0: /* FC transport. */ if (i + 24 > transportid_len) { goto illegal_req; } memcpy(id->n_port_name, ¶m[i + 8], 8); j += offsetof(struct transportid, n_port_name[8]); i += 24; break; case 5: case 0x45: /* iSCSI transport. */ len = lduw_be_p(¶m[i + 2]); if (len > 252 || (len & 3) || i + len + 4 > transportid_len) { /* For format code 00, the standard says the maximum is 223 * plus the NUL terminator. For format code 01 there is no * maximum length, but libmpathpersist ignores the first * byte of id->iscsi_name so our maximum is 252. */ goto illegal_req; } if (memchr(¶m[i + 4], 0, len) == NULL) { goto illegal_req; } memcpy(id->iscsi_name, ¶m[i + 2], len + 2); j += offsetof(struct transportid, iscsi_name[len + 2]); i += len + 4; break; case 6: /* SAS transport. */ if (i + 24 > transportid_len) { goto illegal_req; } memcpy(id->sas_address, ¶m[i + 4], 8); j += offsetof(struct transportid, sas_address[8]); i += 24; break; default: illegal_req: scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM)); return CHECK_CONDITION; } paramp.trnptid_list[paramp.num_transportid++] = id; } }