/*! Check scsi status, using sense if available. */ static err_res check_scsi_status(scsi_periph_device_info *device, scsi_ccb *request) { SHOW_FLOW(3, "%d", request->device_status & SCSI_STATUS_MASK); switch (request->device_status & SCSI_STATUS_MASK) { case SCSI_STATUS_GOOD: // shouldn't happen (cam_status should be CAM_REQ_CMP) return MK_ERROR(err_act_ok, B_OK); case SCSI_STATUS_CHECK_CONDITION: return check_sense(device, request); case SCSI_STATUS_QUEUE_FULL: // SIM should have automatically requeued request, fall through case SCSI_STATUS_BUSY: // take deep breath and try again snooze(1000000); return MK_ERROR(err_act_retry, B_DEV_TIMEOUT); case SCSI_STATUS_COMMAND_TERMINATED: return MK_ERROR(err_act_retry, B_INTERRUPTED); default: return MK_ERROR(err_act_retry, B_ERROR); } }
static err_res wait_for_ready(scsi_periph_device_info *device, scsi_ccb *request) { int retries = 0; while (true) { err_res res; // we send TURs until the device is OK or all hope is lost res = send_tur(device, request); switch (res.action) { case err_act_ok: return MK_ERROR(err_act_ok, B_OK); case err_act_retry: if (++retries >= 3) return MK_ERROR(err_act_fail, res.error_code); break; case err_act_many_retries: if (++retries >= 30) return MK_ERROR(err_act_fail, res.error_code); break; default: SHOW_FLOW( 3, "action: %x, error: %x", (int)res.action, (int)res.error_code); return res; } } }
static void H_stats(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->instance; lcb_error_t rc; lcb_server_stat_resp_t resp; mc_REQDATAEX *exdata; MK_ERROR(root, rc, response, immerr); resp.version = 0; exdata = request->u_rdata.exdata; if (rc != LCB_SUCCESS || PACKET_NKEY(response) == 0) { /* Call the handler without a response, this indicates that this server * has finished responding */ exdata->callback(pipeline, request, rc, NULL); return; } if ((resp.v.v0.nkey = PACKET_NKEY(response))) { resp.v.v0.key = PACKET_KEY(response); if ((resp.v.v0.nbytes = PACKET_NVALUE(response))) { resp.v.v0.bytes = PACKET_VALUE(response); } } exdata->callback(pipeline, request, rc, &resp); }
static void H_stats(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->cqdata; lcb_RESPSTATS resp = { 0 }; mc_REQDATAEX *exdata; MK_ERROR(root, &resp, response, immerr); resp.version = 0; exdata = request->u_rdata.exdata; if (resp.rc != LCB_SUCCESS || PACKET_NKEY(response) == 0) { /* Call the handler without a response, this indicates that this server * has finished responding */ exdata->procs->handler(pipeline, request, resp.rc, NULL); return; } if ((resp.nkey = PACKET_NKEY(response))) { resp.key = PACKET_KEY(response); if ((resp.value = PACKET_VALUE(response))) { resp.nvalue = PACKET_NVALUE(response); } } exdata->procs->handler(pipeline, request, resp.rc, &resp); }
static void H_getreplica(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_error_t rc; lcb_get_resp_t resp; lcb_t instance = pipeline->parent->instance; void *freeptr = NULL; MK_RESPKEY(&resp, 0, request); MK_ERROR(instance, rc, response, immerr); resp.version = 0; if (rc == LCB_SUCCESS) { const protocol_binary_response_get *get = PACKET_EPHEMERAL_START(response); resp.v.v0.cas = PACKET_CAS(response); resp.v.v0.datatype = PACKET_DATATYPE(response); resp.v.v0.flags = ntohl(get->message.body.flags); resp.v.v0.bytes = PACKET_VALUE(response); resp.v.v0.nbytes = PACKET_NVALUE(response); } maybe_decompress(instance, response, &resp, &freeptr); request->u_rdata.exdata->callback(pipeline, request, rc, &resp); free(freeptr); }
static void init_resp3(lcb_t instance, const packet_info *mc_resp, const mc_PACKET *req, lcb_error_t immerr, lcb_RESPBASE *resp) { MK_ERROR(instance, resp, mc_resp, immerr); resp->cas = PACKET_CAS(mc_resp); resp->cookie = (void *)MCREQ_PKT_COOKIE(req); mcreq_get_key(req, &resp->key, &resp->nkey); }
static void H_flush(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->cqdata; lcb_RESPFLUSH resp = { 0 }; mc_REQDATAEX *exdata = request->u_rdata.exdata; MK_ERROR(root, &resp, response, immerr); exdata->procs->handler(pipeline, request, resp.rc, &resp); }
static void H_config(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { /** We just jump to the normal config handler */ lcb_error_t rc; mc_REQDATAEX *exdata = request->u_rdata.exdata; MK_ERROR(pipeline->parent->instance, rc, response, immerr); exdata->callback(pipeline, request, rc, response); }
static void H_config(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { /** We just jump to the normal config handler */ lcb_RESPBASE dummy; mc_REQDATAEX *exdata = request->u_rdata.exdata; MK_ERROR(pipeline->parent->cqdata, &dummy, response, immerr); exdata->procs->handler(pipeline, request, dummy.rc, response); }
static void H_flush(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->instance; lcb_error_t rc; lcb_flush_resp_t resp; mc_REQDATAEX *exdata = request->u_rdata.exdata; MK_ERROR(root, rc, response, immerr); exdata->callback(pipeline, request, rc, &resp); }
static void H_verbosity(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->cqdata; lcb_RESPBASE dummy = { 0 }; mc_REQDATAEX *exdata = request->u_rdata.exdata; MK_ERROR(root, &dummy, response, immerr); exdata->procs->handler(pipeline, request, dummy.rc, NULL); }
static void H_unlock(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->instance; lcb_unlock_resp_t resp; lcb_error_t rc; MK_ERROR(root, rc, response, immerr); MK_RESPKEY(&resp, 0, request); root->callbacks.unlock(root, MCREQ_PKT_RDATA(request)->cookie, rc, &resp); }
static void H_touch(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->instance; lcb_touch_resp_t resp; lcb_error_t rc; MK_ERROR(root, rc, response, immerr); MK_RESPKEY(&resp, 0, request); SET_RESP_CAS(&resp, 0, PACKET_CAS(response)); resp.version = 0; root->callbacks.touch(root, MCREQ_PKT_RDATA(request)->cookie, rc, &resp); }
static void H_delete(mc_PIPELINE *pipeline, mc_PACKET *packet, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->instance; lcb_error_t rc; lcb_remove_resp_t resp; resp.version = 0; SET_RESP_CAS(&resp, 0, PACKET_CAS(response)); MK_RESPKEY(&resp, 0, packet); MK_ERROR(root, rc, response, immerr); INVOKE_CALLBACK(packet, root->callbacks.remove, (root, MCREQ_PKT_COOKIE(packet), rc, &resp)); }
static void H_version(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->cqdata; lcb_RESPMCVERSION resp = { 0 }; mc_REQDATAEX *exdata = request->u_rdata.exdata; MK_ERROR(root, &resp, response, immerr); if (PACKET_NBODY(response)) { resp.mcversion = response->payload; resp.nversion = PACKET_NBODY(response); } exdata->procs->handler(pipeline, request, resp.rc, &resp); }
static void H_arithmetic(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->instance; lcb_error_t rc; lcb_arithmetic_resp_t resp; MK_ERROR(root, rc, response, immerr); if (rc == LCB_SUCCESS) { memcpy(&resp.v.v0.value, response->payload, sizeof(resp.v.v0.value)); resp.v.v0.value = ntohll(resp.v.v0.value); } MK_RESPKEY(&resp, 0, request); SET_RESP_CAS(&resp, 0, PACKET_CAS(response)); INVOKE_CALLBACK(request, root->callbacks.arithmetic, (root, MCREQ_PKT_COOKIE(request), rc, &resp)); }
static void H_version(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->instance; lcb_error_t rc; lcb_server_version_resp_t resp; mc_REQDATAEX *exdata = request->u_rdata.exdata; MK_ERROR(root, rc, response, immerr); if (PACKET_NBODY(response)) { resp.v.v0.vstring = response->payload; resp.v.v0.nvstring = PACKET_NBODY(response); } exdata->callback(pipeline, request, rc, &resp); }
static void H_store(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->instance; lcb_storage_t op; lcb_error_t rc; lcb_store_resp_t resp; MK_ERROR(root, rc, response, immerr); switch (PACKET_OPCODE(response)) { case PROTOCOL_BINARY_CMD_ADD: op = LCB_ADD; break; case PROTOCOL_BINARY_CMD_REPLACE: op = LCB_REPLACE; break; case PROTOCOL_BINARY_CMD_SET: op = LCB_SET; break; case PROTOCOL_BINARY_CMD_APPEND: op = LCB_APPEND; break; case PROTOCOL_BINARY_CMD_PREPEND: op = LCB_PREPEND; break; default: abort(); break; } resp.version = 0; MK_RESPKEY(&resp, 0, request); SET_RESP_CAS(&resp, 0, PACKET_CAS(response)); INVOKE_CALLBACK(request, root->callbacks.store, (root, MCREQ_PKT_COOKIE(request), op, rc, &resp)); }
static void H_get(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_error_t rc; lcb_t o; lcb_get_resp_t resp; void *freeptr = NULL; o = pipeline->parent->instance; MK_RESPKEY(&resp, 0, request); MK_ERROR(o, rc, response, immerr); resp.version = 0; if (rc == LCB_SUCCESS) { const protocol_binary_response_getq *getq = PACKET_EPHEMERAL_START(response); resp.v.v0.cas = PACKET_CAS(response); resp.v.v0.datatype = PACKET_DATATYPE(response); resp.v.v0.flags = ntohl(getq->message.body.flags); resp.v.v0.bytes = PACKET_VALUE(response); resp.v.v0.nbytes = PACKET_NVALUE(response); rc = LCB_SUCCESS; } else { resp.v.v0.cas = 0; resp.v.v0.nbytes = 0; resp.v.v0.bytes = NULL; resp.v.v0.flags = 0; } maybe_decompress(o, response, &resp, &freeptr); INVOKE_CALLBACK(request, o->callbacks.get, (o, MCREQ_PKT_COOKIE(request), rc, &resp)); free(freeptr); }
static void H_observe(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->instance; lcb_error_t rc; uint32_t ttp; uint32_t ttr; lcb_size_t pos; VBUCKET_CONFIG_HANDLE config; const char *end, *ptr; mc_REQDATAEX *rd = request->u_rdata.exdata; MK_ERROR(root, rc, response, immerr); if (rc != LCB_SUCCESS) { if (! (request->flags & MCREQ_F_INVOKED)) { rd->callback(pipeline, request, rc, NULL); } return; } /** The CAS field is split into TTP/TTR values */ ptr = (char *)&response->res.response.cas; memcpy(&ttp, ptr, sizeof(ttp)); memcpy(&ttr, ptr + sizeof(ttp), sizeof(ttp)); ttp = ntohl(ttp); ttr = ntohl(ttr); /** Actual payload sequence of (vb, nkey, key). Repeats multiple times */ ptr = response->payload; end = (char *)ptr + PACKET_NBODY(response); config = pipeline->parent->config; for (pos = 0; ptr < end; pos++) { lcb_cas_t cas; lcb_uint8_t obs; lcb_uint16_t nkey, vb; const char *key; lcb_observe_resp_t resp; memset(&resp, 0, sizeof(resp)); memcpy(&vb, ptr, sizeof(vb)); vb = ntohs(vb); ptr += sizeof(vb); memcpy(&nkey, ptr, sizeof(nkey)); nkey = ntohs(nkey); ptr += sizeof(nkey); key = (const char *)ptr; ptr += nkey; obs = *((lcb_uint8_t *)ptr); ptr += sizeof(obs); memcpy(&cas, ptr, sizeof(cas)); ptr += sizeof(cas); resp.v.v0.key = key; resp.v.v0.nkey = nkey; resp.v.v0.cas = cas; resp.v.v0.status = obs; resp.v.v0.ttp = 0; resp.v.v0.ttr = 0; resp.v.v0.from_master = pipeline->index == vbucket_get_master(config, vb); if (! (request->flags & MCREQ_F_INVOKED)) { rd->callback(pipeline, request, rc, &resp); } } }
static void H_observe(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->cqdata; uint32_t ttp; uint32_t ttr; lcb_size_t pos; lcbvb_CONFIG* config; const char *end, *ptr; mc_REQDATAEX *rd = request->u_rdata.exdata; lcb_RESPOBSERVE resp = { 0 }; MK_ERROR(root, &resp, response, immerr); if (resp.rc != LCB_SUCCESS) { if (! (request->flags & MCREQ_F_INVOKED)) { rd->procs->handler(pipeline, request, resp.rc, NULL); } return; } /** The CAS field is split into TTP/TTR values */ ptr = (char *)&response->res.response.cas; memcpy(&ttp, ptr, sizeof(ttp)); memcpy(&ttr, ptr + sizeof(ttp), sizeof(ttp)); ttp = ntohl(ttp); ttr = ntohl(ttr); /** Actual payload sequence of (vb, nkey, key). Repeats multiple times */ ptr = response->payload; end = (char *)ptr + PACKET_NBODY(response); config = pipeline->parent->config; for (pos = 0; ptr < end; pos++) { lcb_cas_t cas; lcb_uint8_t obs; lcb_uint16_t nkey, vb; const char *key; memcpy(&vb, ptr, sizeof(vb)); vb = ntohs(vb); ptr += sizeof(vb); memcpy(&nkey, ptr, sizeof(nkey)); nkey = ntohs(nkey); ptr += sizeof(nkey); key = (const char *)ptr; ptr += nkey; obs = *((lcb_uint8_t *)ptr); ptr += sizeof(obs); memcpy(&cas, ptr, sizeof(cas)); ptr += sizeof(cas); resp.key = key; resp.nkey = nkey; resp.cas = cas; resp.status = obs; resp.ismaster = pipeline->index == lcbvb_vbmaster(config, vb); resp.ttp = 0; resp.ttr = 0; TRACE_OBSERVE_PROGRESS(response, &resp); if (! (request->flags & MCREQ_F_INVOKED)) { rd->procs->handler(pipeline, request, resp.rc, &resp); } } TRACE_OBSERVE_END(response); }
/*! Check result of request * 1. check SCSI subsystem problems * 2. if request hit device, check SCSI status * 3. if request got executed, check sense */ err_res periph_check_error(scsi_periph_device_info *device, scsi_ccb *request) { SHOW_FLOW(4, "%d", request->subsys_status & SCSI_SUBSYS_STATUS_MASK); switch (request->subsys_status & SCSI_SUBSYS_STATUS_MASK) { // everything is ok case SCSI_REQ_CMP: return MK_ERROR(err_act_ok, B_OK); // no device case SCSI_LUN_INVALID: case SCSI_TID_INVALID: case SCSI_PATH_INVALID: case SCSI_DEV_NOT_THERE: case SCSI_NO_HBA: SHOW_ERROR0(2, "No device"); return MK_ERROR(err_act_fail, B_DEV_BAD_DRIVE_NUM); // device temporary unavailable case SCSI_SEL_TIMEOUT: case SCSI_BUSY: case SCSI_SCSI_BUSY: case SCSI_HBA_ERR: case SCSI_MSG_REJECT_REC: case SCSI_NO_NEXUS: case SCSI_FUNC_NOTAVAIL: case SCSI_RESRC_UNAVAIL: // take a deep breath and hope device becomes ready snooze(1000000); return MK_ERROR(err_act_retry, B_DEV_TIMEOUT); // data transmission went wrong case SCSI_DATA_RUN_ERR: case SCSI_UNCOR_PARITY: SHOW_ERROR0(2, "Data transmission failed"); // retry immediately return MK_ERROR(err_act_retry, B_DEV_READ_ERROR); // request broken case SCSI_REQ_INVALID: SHOW_ERROR0(2, "Invalid request"); return MK_ERROR(err_act_fail, B_ERROR); // request aborted case SCSI_REQ_ABORTED: case SCSI_SCSI_BUS_RESET: case SCSI_REQ_TERMIO: case SCSI_UNEXP_BUSFREE: case SCSI_BDR_SENT: case SCSI_CMD_TIMEOUT: case SCSI_IID_INVALID: case SCSI_UNACKED_EVENT: case SCSI_IDE: case SCSI_SEQUENCE_FAIL: // take a small breath and retry snooze(100000); return MK_ERROR(err_act_retry, B_DEV_TIMEOUT); // device error case SCSI_REQ_CMP_ERR: return check_scsi_status(device, request); // device error, but we don't know what happened case SCSI_AUTOSENSE_FAIL: SHOW_ERROR0(2, "Auto-sense failed, don't know what really happened"); return MK_ERROR(err_act_fail, B_ERROR); // should not happen, give up case SCSI_BUS_RESET_DENIED: case SCSI_PROVIDE_FAIL: case SCSI_UA_TERMIO: case SCSI_CDB_RECVD: case SCSI_LUN_ALLREADY_ENAB: // supposed to fall through default: return MK_ERROR(err_act_fail, B_ERROR); } }
/*! Decode sense data and generate error code. */ static err_res check_sense(scsi_periph_device_info *device, scsi_ccb *request) { scsi_sense *sense = (scsi_sense *)request->sense; if ((request->subsys_status & SCSI_AUTOSNS_VALID) == 0) { SHOW_ERROR0(2, "No auto-sense (but there should be)"); // shouldn't happen (cam_status should be CAM_AUTOSENSE_FAIL // as we asked for autosense) return MK_ERROR(err_act_fail, B_ERROR); } if (SCSI_MAX_SENSE_SIZE - request->sense_resid < (int)offsetof(scsi_sense, add_sense_length) + 1) { SHOW_ERROR(2, "sense too short (%d bytes)", SCSI_MAX_SENSE_SIZE - request->sense_resid); // that's a bit too short return MK_ERROR(err_act_fail, B_ERROR); } switch (sense->error_code) { case SCSIS_DEFERRED_ERROR: // we are doomed - some previous request turned out to have failed // we neither know which one nor can we resubmit it SHOW_ERROR0(2, "encountered DEFERRED ERROR - bye, bye"); return MK_ERROR(err_act_ok, B_OK); case SCSIS_CURR_ERROR: // we start with very specific and finish very general error infos switch ((sense->asc << 8) | sense->ascq) { case SCSIS_ASC_AUDIO_PLAYING: SHOW_INFO0(2, "busy because playing audio"); // we need something like "busy" return MK_ERROR(err_act_fail, B_DEV_NOT_READY); case SCSIS_ASC_LUN_NEED_INIT: SHOW_INFO0(2, "LUN needs init"); // reported by some devices that are idle and spun down // sending START UNIT should awake them return MK_ERROR(err_act_start, B_NO_INIT); case SCSIS_ASC_LUN_NEED_MANUAL_HELP: SHOW_ERROR0(2, "LUN needs manual help"); return MK_ERROR(err_act_fail, B_DEV_NOT_READY); case SCSIS_ASC_LUN_FORMATTING: SHOW_INFO0(2, "LUN is formatting"); // we could wait, but as formatting normally takes quite long, // we give up without any further retries return MK_ERROR(err_act_fail, B_DEV_NOT_READY); case SCSIS_ASC_MEDIUM_CHANGED: SHOW_FLOW0(3, "Medium changed"); periph_media_changed(device, request); return MK_ERROR(err_act_fail, B_DEV_MEDIA_CHANGED); case SCSIS_ASC_WRITE_ERR_AUTOREALLOC: SHOW_ERROR0(2, "Recovered write error - block got reallocated automatically"); return MK_ERROR(err_act_ok, B_OK); case SCSIS_ASC_ID_RECOV: SHOW_ERROR0(2, "Recovered ID with ECC"); return MK_ERROR(err_act_ok, B_OK); case SCSIS_ASC_REMOVAL_REQUESTED: SHOW_INFO0(2, "Removal requested"); mutex_lock(&device->mutex); device->removal_requested = true; mutex_unlock(&device->mutex); return MK_ERROR(err_act_retry, B_DEV_MEDIA_CHANGE_REQUESTED); case SCSIS_ASC_LUN_BECOMING_READY: SHOW_INFO0(2, "Becoming ready"); // wait a bit - the device needs some time snooze(100000); return MK_ERROR(err_act_many_retries, B_DEV_NOT_READY); case SCSIS_ASC_WAS_RESET: SHOW_INFO0(2, "Unit was reset"); // TBD: need a better error code here // as some earlier command led to the reset, we are innocent return MK_ERROR(err_act_retry, B_DEV_NOT_READY); } switch (sense->asc) { case SCSIS_ASC_DATA_RECOV_NO_ERR_CORR >> 8: case SCSIS_ASC_DATA_RECOV_WITH_CORR >> 8: // these are the groups of recovered data with or without correction // we should print at least a warning here SHOW_ERROR(0, "Recovered data, asc=0x%2x, ascq=0x%2x", sense->asc, sense->ascq); return MK_ERROR(err_act_ok, B_OK); case SCSIS_ASC_WRITE_PROTECTED >> 8: SHOW_ERROR0( 2, "Write protected" ); // isn't there any proper "write protected" error code? return MK_ERROR(err_act_fail, B_READ_ONLY_DEVICE); case SCSIS_ASC_NO_MEDIUM >> 8: SHOW_FLOW0(2, "No medium"); return MK_ERROR(err_act_fail, B_DEV_NO_MEDIA); } // we issue this info very late, so we don't clutter syslog with // messages about changed or missing media SHOW_ERROR(3, "0x%04x", (sense->asc << 8) | sense->ascq); switch (sense->sense_key) { case SCSIS_KEY_NO_SENSE: SHOW_ERROR0(2, "No sense"); // we thought there was an error, huh? return MK_ERROR(err_act_ok, B_OK); case SCSIS_KEY_RECOVERED_ERROR: SHOW_ERROR0(2, "Recovered error"); // we should probably tell about that; perhaps tomorrow return MK_ERROR(err_act_ok, B_OK); case SCSIS_KEY_NOT_READY: return MK_ERROR(err_act_retry, B_DEV_NOT_READY); case SCSIS_KEY_MEDIUM_ERROR: SHOW_ERROR0(2, "Medium error"); return MK_ERROR( err_act_retry, B_DEV_RECALIBRATE_ERROR); case SCSIS_KEY_HARDWARE_ERROR: SHOW_ERROR0(2, "Hardware error"); return MK_ERROR(err_act_retry, B_DEV_SEEK_ERROR); case SCSIS_KEY_ILLEGAL_REQUEST: SHOW_ERROR0(2, "Illegal request"); return MK_ERROR(err_act_invalid_req, B_ERROR); case SCSIS_KEY_UNIT_ATTENTION: SHOW_ERROR0(2, "Unit attention"); return MK_ERROR( err_act_retry, B_DEV_NOT_READY); case SCSIS_KEY_DATA_PROTECT: SHOW_ERROR0(2, "Data protect"); // we could set "permission denied", but that's probably // irritating to the user return MK_ERROR(err_act_fail, B_NOT_ALLOWED); case SCSIS_KEY_BLANK_CHECK: SHOW_ERROR0(2, "Is blank"); return MK_ERROR(err_act_fail, B_DEV_UNREADABLE); case SCSIS_KEY_VENDOR_SPECIFIC: return MK_ERROR(err_act_fail, B_ERROR); case SCSIS_KEY_COPY_ABORTED: // we don't use copy, so this is really wrong return MK_ERROR(err_act_fail, B_ERROR); case SCSIS_KEY_ABORTED_COMMAND: // proper error code? return MK_ERROR(err_act_retry, B_ERROR); case SCSIS_KEY_EQUAL: case SCSIS_KEY_MISCOMPARE: // we don't search, so this is really wrong return MK_ERROR(err_act_fail, B_ERROR); case SCSIS_KEY_VOLUME_OVERFLOW: // not the best return code, but this error doesn't apply // to devices we currently support return MK_ERROR(err_act_fail, B_DEV_SEEK_ERROR); case SCSIS_KEY_RESERVED: default: return MK_ERROR(err_act_fail, B_ERROR); } default: // shouldn't happen - there are only 2 error codes defined SHOW_ERROR(2, "Invalid sense type (0x%x)", sense->error_code); return MK_ERROR(err_act_fail, B_ERROR); } }