/* Similar to _v2 but takes a pointer to an object (derived from) sg_pt_base. * That object is assumed to be constructed and have a device file descriptor * associated with it. Caller is responsible for lifetime of ptp. */ int sg_ll_inquiry_pt(struct sg_pt_base * ptvp, bool evpd, int pg_op, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int verbose) { clear_scsi_pt_obj(ptvp); return sg_ll_inquiry_com(ptvp, false, evpd, pg_op, resp, mx_resp_len, timeout_secs, residp, noisy, verbose); }
/* Invokes a SCSI START STOP UNIT command (SBC + MMC). * Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors. * SBC-3 and MMC partially overlap on the power_condition_modifier(sbc) and * format_layer_number(mmc) fields. They also overlap on the noflush(sbc) * and fl(mmc) one bit field. This is the cause of the awkardly named * pc_mod__fl_num and noflush__fl arguments to this function. * */ int sg_ll_start_stop_unit_pt(struct sg_pt_base * ptvp, bool immed, int pc_mod__fl_num, int power_cond, bool noflush__fl, bool loej, bool start, bool noisy, int verbose) { static const char * const cdb_s = "start stop unit"; int k, res, ret, sense_cat; uint8_t ssuBlk[START_STOP_CMDLEN] = {START_STOP_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN]; if (immed) ssuBlk[1] = 0x1; ssuBlk[3] = pc_mod__fl_num & 0xf; /* bits 2 and 3 are reserved in MMC */ ssuBlk[4] = ((power_cond & 0xf) << 4); if (noflush__fl) ssuBlk[4] |= 0x4; if (loej) ssuBlk[4] |= 0x2; if (start) ssuBlk[4] |= 0x1; if (verbose) { pr2ws(" %s command:", cdb_s); for (k = 0; k < (int)sizeof(ssuBlk); ++k) pr2ws(" %02x", ssuBlk[k]); pr2ws("\n"); } clear_scsi_pt_obj(ptvp); set_scsi_pt_cdb(ptvp, ssuBlk, sizeof(ssuBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, -1, START_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; return ret; }
/* Returns number of TURs performed */ static int loop_turs(struct sg_pt_base * ptvp, struct loop_res_t * resp, struct opts_t * op) { int k, res; int vb = op->verbose; char b[80]; if (op->do_low) { int rs, n, sense_cat; uint8_t cdb[6]; uint8_t sense_b[32]; for (k = 0; k < op->do_number; ++k) { /* Might get Unit Attention on first invocation */ memset(cdb, 0, sizeof(cdb)); /* TUR's cdb is 6 zeros */ set_scsi_pt_cdb(ptvp, cdb, sizeof(cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); rs = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, vb); n = sg_cmds_process_resp(ptvp, "Test unit ready", rs, (0 == k), vb, &sense_cat); if (-1 == n) { resp->ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); return k; } else if (-2 == n) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: break; case SG_LIB_CAT_NOT_READY: ++resp->num_errs; if (1 == op->do_number) { resp->ret = sense_cat; printf("device not ready\n"); resp->reported = true; } break; case SG_LIB_CAT_UNIT_ATTENTION: ++resp->num_errs; if (vb) { pr2serr("Ignoring Unit attention (sense key)\n"); resp->reported = true; } break; default: ++resp->num_errs; if (1 == op->do_number) { resp->ret = sense_cat; sg_get_category_sense_str(sense_cat, sizeof(b), b, vb); printf("%s\n", b); resp->reported = true; return k; } break; } } clear_scsi_pt_obj(ptvp); } return k; } else { for (k = 0; k < op->do_number; ++k) { /* Might get Unit Attention on first invocation */ res = sg_ll_test_unit_ready_pt(ptvp, k, (0 == k), vb); if (res) { ++resp->num_errs; resp->ret = res; if (1 == op->do_number) { if (SG_LIB_CAT_NOT_READY == res) printf("device not ready\n"); else { sg_get_category_sense_str(res, sizeof(b), b, vb); printf("%s\n", b); } resp->reported = true; break; } } } return k; } }