ATF_TC_BODY(cam_freeccb_negative_test_NULL, tc) { cam_clear_error(); cam_freeccb(NULL); ATF_REQUIRE(!cam_has_error()); }
void destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp) { if (ptp->ccb) cam_freeccb(ptp->ccb); free(ptp); } }
static int doCAM(isess_t *sess) { char pathstr[1024]; union ccb *ccb; int i, n; if(ioctl(sess->fd, ISCSIGETCAM, &sess->cam) != 0) { syslog(LOG_WARNING, "ISCSIGETCAM failed: %d", errno); return 0; } debug(1, "nluns=%d", sess->cam.target_nluns); /* | for now will do this for each lun ... */ for(n = i = 0; i < sess->cam.target_nluns; i++) { debug(2, "CAM path_id=%d target_id=%d", sess->cam.path_id, sess->cam.target_id); sess->camdev = cam_open_btl(sess->cam.path_id, sess->cam.target_id, i, O_RDWR, NULL); if(sess->camdev == NULL) { //syslog(LOG_WARNING, "%s", cam_errbuf); debug(3, "%s", cam_errbuf); continue; } cam_path_string(sess->camdev, pathstr, sizeof(pathstr)); debug(2, "pathstr=%s", pathstr); ccb = cam_getccb(sess->camdev); CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->crs); ccb->ccb_h.func_code = XPT_REL_SIMQ; ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS; ccb->crs.openings = sess->op->tags; if(cam_send_ccb(sess->camdev, ccb) < 0) debug(2, "%s", cam_errbuf); else if((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { syslog(LOG_WARNING, "XPT_REL_SIMQ CCB failed"); // cam_error_print(sess->camdev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); } else { n++; syslog(LOG_INFO, "%s tagged openings now %d\n", pathstr, ccb->crs.openings); } cam_freeccb(ccb); cam_close_device(sess->camdev); } return n; }
/* send a command to the drive */ int ata_cmd(ATA *ata, enum ata_command atacmd, int drivercmd) { int rc = 0; if (atacmd > 0) ata->atacmd.ata_cmd.u.ata.command = atacmd; switch (ata->access_mode) { case ACCESS_MODE_ATA: if (drivercmd == IOCATAGMAXCHANNEL) { int maxchan = 0; rc = ioctl( ata->devhandle.fd, drivercmd, &maxchan ); ata->atacmd.ata_cmd.data = malloc(sizeof(int)); *ata->atacmd.ata_cmd.data = maxchan; } else { rc = ioctl( ata->devhandle.fd, IOCATAREQUEST, &(ata->atacmd.ata_cmd) ); } break; case ACCESS_MODE_SAT: if (drivercmd == IOCATAGMAXCHANNEL) { /* XXX hardcoded to 1 channel */ rc = 0; ata->atacmd.ata_cmd.data = malloc(sizeof(int)); /* memory leak (above too) */ *ata->atacmd.ata_cmd.data = 1; } else { union ccb * ccb; struct ccb_scsiio * csio; ccb = cam_getccb(ata->devhandle.camdev); if (!ccb) return -1; csio = &ccb->csio; rc = translate_ata_to_csio(csio, ata, atacmd, drivercmd); if (rc) return rc; rc = cam_send_ccb(ata->devhandle.camdev, ccb); cam_freeccb(ccb); if (rc) return rc; } break; } return rc; }
ATF_TC_BODY(cam_getccb_positive_test, tc) { union ccb *cam_ccb; struct cam_device *cam_dev; const char *cam_test_device; cam_test_device = get_cam_test_device(tc); cam_clear_error(); cam_dev = cam_open_device(cam_test_device, O_RDWR); ATF_CHECK_MSG(cam_dev != NULL, "cam_open_device failed: %s", cam_errbuf); ATF_REQUIRE(!cam_has_error()); cam_ccb = cam_getccb(cam_dev); ATF_CHECK_MSG(cam_ccb != NULL, "get_camccb failed: %s", cam_errbuf); ATF_REQUIRE(!cam_has_error()); cam_freeccb(cam_ccb); cam_close_device(cam_dev); }
ndmp9_error ndmos_scsi_execute_cdb (struct ndm_session *sess, ndmp9_execute_cdb_request *request, ndmp9_execute_cdb_reply *reply) { struct ndm_robot_agent *robot = sess->robot_acb; struct cam_device * camdev = robot->camdev; union ccb * ccb; u_int32_t flags; u_int8_t * data_ptr = 0; u_int8_t * data_in_ptr = 0; u_int32_t data_len = 0; u_int32_t data_done; int rc; NDMOS_MACRO_ZEROFILL (reply); reply->error = NDMP9_IO_ERR; /* pessimistic */ ccb = cam_getccb(camdev); if (!ccb) { reply->error = NDMP9_NO_MEM_ERR; return reply->error; } switch (request->data_dir) { case NDMP9_SCSI_DATA_DIR_NONE: flags = CAM_DIR_NONE; break; case NDMP9_SCSI_DATA_DIR_IN: if (data_len > 1024*1024) { reply->error = NDMP9_ILLEGAL_ARGS_ERR; goto out; } data_len = request->datain_len; data_in_ptr = malloc (data_len); if (!data_in_ptr) { reply->error = NDMP9_NO_MEM_ERR; goto out; } data_ptr = data_in_ptr; flags = CAM_DIR_IN; break; case NDMP9_SCSI_DATA_DIR_OUT: data_len = request->dataout.dataout_len; data_ptr = request->dataout.dataout_val; flags = CAM_DIR_OUT; break; default: return NDMP9_ILLEGAL_ARGS_ERR; break; } bcopy(request->cdb.cdb_val, &ccb->csio.cdb_io.cdb_bytes, request->cdb.cdb_len); cam_fill_csio(&ccb->csio, /*retries*/ 1, /*cbfcnp*/ NULL, /*flags*/ flags, /*tag_action*/ MSG_SIMPLE_Q_TAG, /*data_ptr*/ data_ptr, /*dxfer_len*/ data_len, /*sense_len*/ SSD_FULL_SIZE, /*cdb_len*/ request->cdb.cdb_len, /*timeout*/ request->timeout); rc = cam_send_ccb (camdev, ccb); if (rc != 0) { reply->error = NDMP9_IO_ERR; goto out; } switch (ccb->csio.ccb_h.status & CAM_STATUS_MASK) { case CAM_REQ_CMP: /* completed */ reply->error = NDMP9_NO_ERR; break; case CAM_SEL_TIMEOUT: case CAM_CMD_TIMEOUT: reply->error = NDMP9_TIMEOUT_ERR; break; case CAM_SCSI_STATUS_ERROR: if (ccb->csio.ccb_h.status & CAM_AUTOSNS_VALID) { int n_sense; n_sense = ccb->csio.sense_len - ccb->csio.sense_resid; reply->ext_sense.ext_sense_val = malloc (n_sense); if (reply->ext_sense.ext_sense_val) { bcopy (&ccb->csio.sense_data, reply->ext_sense.ext_sense_val, n_sense); reply->ext_sense.ext_sense_len = n_sense; } } reply->error = NDMP9_NO_ERR; break; default: reply->error = NDMP9_IO_ERR; break; } out: if (reply->error == NDMP9_NO_ERR) { reply->status = ccb->csio.scsi_status; data_done = data_len - ccb->csio.resid; switch (request->data_dir) { case NDMP9_SCSI_DATA_DIR_NONE: break; case NDMP9_SCSI_DATA_DIR_IN: reply->datain.datain_val = data_in_ptr; reply->datain.datain_len = data_len; break; case NDMP9_SCSI_DATA_DIR_OUT: reply->dataout_len = data_len; break; default: break; } } else { if (data_in_ptr) { free (data_in_ptr); data_in_ptr = 0; } } cam_freeccb (ccb); return reply->error; }
/* * Core interface function to lowlevel SCSI interface. */ static inline bool do_scsi_cmd_page(int fd, const char *device_name, void *cdb, unsigned int cdb_len, void *cmd_page, unsigned int cmd_page_len, int direction) { int unitnum, len; union ccb *ccb; char errbuf[128]; char cam_devicename[64]; struct cam_device *cam_dev; SCSI_PAGE_SENSE sense; bool retval = false; /* * See what CAM device to use. */ if (cam_get_device(device_name, cam_devicename, sizeof(cam_devicename), &unitnum) == -1) { berrno be; Emsg2(M_ERROR, 0, _("Failed to find CAM device for %s: ERR=%s\n"), device_name, be.bstrerror()); Dmsg2(010, "Failed to find CAM device for %s: ERR=%s\n", device_name, be.bstrerror()); return false; } cam_dev = cam_open_spec_device(cam_devicename, unitnum, O_RDWR, NULL); if (!cam_dev) { berrno be; Emsg2(M_ERROR, 0, _("Failed to open CAM device for %s: ERR=%s\n"), device_name, be.bstrerror()); Dmsg2(010, "Failed to open CAM device for %s: ERR=%s\n", device_name, be.bstrerror()); return false; } ccb = cam_getccv(cam_dev); if (!ccb) { Emsg1(M_ERROR, 0, _("Failed to allocate new ccb for %s\n"), device_name); Dmsg1(0, "Failed to allocate new ccb for %s\n", device_name); goto bail_out; } /* * Clear out structure, except for header that was filled for us. */ memset(&ccb->ccb_h)[1], 0, sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); cam_fill_csio(&ccb->csio, 1, /* retries */ NULL, /* cbfcnp */ direction, /* flags */ MSG_SIMPLE_Q_TAG,, /* tagaction */ cmd_page, /* dataptr */ cmd_page_len, /* datalen */ sizeof(sense), /* senselength */ cdb_len, /* cdblength */ 15000 /* timeout (millisecs) */); memcpy(ccb->csio.cdb_io.cdb_bytes, cdb, SPP_SP_CMD_LEN); if (cam_send_ccb(cam_dev, ccb) < 0) { Emsg2(M_ERROR, 0, _("Failed to send ccb to device %s: %s\n"), device_name, cam_error_string(cam_dev, ccb, errbuf, sizeof(errbuf), CAM_ESF_ALL, CAM_EPF_ALL)); Dmsg2(010, "Failed to send ccb to device %s: %s\n", device_name, cam_error_string(cam_dev, ccb, errbuf, sizeof(errbuf), CAM_ESF_ALL, CAM_EPF_ALL)); cam_freeccb(ccb); goto bail_out; } /* * Retrieve the SCSI sense data. */ if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR)) { if ((SAM_STAT_CHECK_CONDITION == ccb->csio.scsi_status) || (SAM_STAT_COMMAND_TERMINATED == ccb->csio.scsi_status)) { len = sizeof(sense) - ccb->csio.sense_resid; if (len) { memcpy(&sense, &(ccb->csio.sense_data), len); } } } retval = true; bail_out: /* * Close the CAM device. */ cam_close_device(cam_dev); return retval; }
/* * Download firmware stored in buf to cam_dev. If simulation mode * is enabled, only show what packet sizes would be sent to the * device but do not sent any actual packets */ static int fw_download_img(struct cam_device *cam_dev, const struct fw_vendor *vp, char *buf, int img_size, int sim_mode, int verbose, int retry_count, int timeout) { struct scsi_write_buffer cdb; union ccb *ccb; int pkt_count = 0; u_int32_t pkt_size = 0; char *pkt_ptr = buf; u_int32_t offset; int last_pkt = 0; if ((ccb = cam_getccb(cam_dev)) == NULL) { warnx("Could not allocate CCB"); return (1); } scsi_test_unit_ready(&ccb->csio, 0, NULL, MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, 5000); /* Disable freezing the device queue. */ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; if (cam_send_ccb(cam_dev, ccb) < 0) { warnx("Error sending test unit ready"); if (verbose) cam_error_print(cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); cam_freeccb(ccb); return(1); } if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { warnx("Device is not ready"); if (verbose) cam_error_print(cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); cam_freeccb(ccb); return (1); } pkt_size = vp->max_pkt_size; if (verbose || sim_mode) { fprintf(stdout, "--------------------------------------------------\n"); fprintf(stdout, "PktNo. PktSize BytesRemaining LastPkt\n"); fprintf(stdout, "--------------------------------------------------\n"); } /* Download single fw packets. */ do { if (img_size <= vp->max_pkt_size) { last_pkt = 1; pkt_size = img_size; } if (verbose || sim_mode) fprintf(stdout, "%3u %5u (0x%05X) %7u (0x%06X) " "%d\n", pkt_count, pkt_size, pkt_size, img_size - pkt_size, img_size - pkt_size, last_pkt); bzero(&cdb, sizeof(cdb)); cdb.opcode = WRITE_BUFFER; cdb.control = 0; /* Parameter list length. */ scsi_ulto3b(pkt_size, &cdb.length[0]); offset = vp->inc_cdb_offset ? (pkt_ptr - buf) : 0; scsi_ulto3b(offset, &cdb.offset[0]); cdb.byte2 = last_pkt ? vp->cdb_byte2_last : vp->cdb_byte2; cdb.buffer_id = vp->inc_cdb_buffer_id ? pkt_count : 0; /* Zero out payload of ccb union after ccb header. */ bzero((u_char *)ccb + sizeof(struct ccb_hdr), sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); /* Copy previously constructed cdb into ccb_scsiio struct. */ bcopy(&cdb, &ccb->csio.cdb_io.cdb_bytes[0], sizeof(struct scsi_write_buffer)); /* Fill rest of ccb_scsiio struct. */ if (!sim_mode) { cam_fill_csio(&ccb->csio, /* ccb_scsiio */ retry_count, /* retries */ NULL, /* cbfcnp */ CAM_DIR_OUT | CAM_DEV_QFRZDIS, /* flags */ CAM_TAG_ACTION_NONE, /* tag_action */ (u_char *)pkt_ptr, /* data_ptr */ pkt_size, /* dxfer_len */ SSD_FULL_SIZE, /* sense_len */ sizeof(struct scsi_write_buffer), /* cdb_len */ timeout ? timeout : CMD_TIMEOUT); /* timeout */ /* Execute the command. */ if (cam_send_ccb(cam_dev, ccb) < 0) { warnx("Error writing image to device"); if (verbose) cam_error_print(cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); goto bailout; } } /* Prepare next round. */ pkt_count++; pkt_ptr += pkt_size; img_size -= pkt_size; } while(!last_pkt); if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if (verbose) cam_error_print(cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); goto bailout; } cam_freeccb(ccb); return (0); bailout: cam_freeccb(ccb); return (1); }
/* * Download firmware stored in buf to cam_dev. If simulation mode * is enabled, only show what packet sizes would be sent to the * device but do not sent any actual packets */ static int fw_download_img(struct cam_device *cam_dev, const struct fw_vendor *vp, char *buf, int img_size, int sim_mode, int printerrors, int retry_count, int timeout, const char *imgname, const char *type) { struct scsi_write_buffer cdb; progress_t progress; int size; union ccb *ccb; int pkt_count = 0; int max_pkt_size; u_int32_t pkt_size = 0; char *pkt_ptr = buf; u_int32_t offset; int last_pkt = 0; int16_t *ptr; if ((ccb = cam_getccb(cam_dev)) == NULL) { warnx("Could not allocate CCB"); return (1); } if (strcmp(type, "scsi") == 0) { scsi_test_unit_ready(&ccb->csio, 0, NULL, MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, 5000); } else if (strcmp(type, "ata") == 0) { /* cam_getccb cleans up the header, caller has to zero the payload */ bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr)); ptr = (uint16_t *)malloc(sizeof(struct ata_params)); if (ptr == NULL) { cam_freeccb(ccb); warnx("can't malloc memory for identify\n"); return(1); } bzero(ptr, sizeof(struct ata_params)); cam_fill_ataio(&ccb->ataio, 1, NULL, /*flags*/CAM_DIR_IN, MSG_SIMPLE_Q_TAG, /*data_ptr*/(uint8_t *)ptr, /*dxfer_len*/sizeof(struct ata_params), timeout ? timeout : 30 * 1000); ata_28bit_cmd(&ccb->ataio, ATA_ATA_IDENTIFY, 0, 0, 0); } else { warnx("weird disk type '%s'", type); return 1; } /* Disable freezing the device queue. */ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; if (cam_send_ccb(cam_dev, ccb) < 0) { warnx("Error sending identify/test unit ready"); if (printerrors) cam_error_print(cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); cam_freeccb(ccb); return(1); } if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { warnx("Device is not ready"); if (printerrors) cam_error_print(cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); cam_freeccb(ccb); return (1); } max_pkt_size = vp->max_pkt_size; if (vp->max_pkt_size == 0 && strcmp(type, "ata") == 0) { max_pkt_size = UNKNOWN_MAX_PKT_SIZE; } pkt_size = vp->max_pkt_size; progress_init(&progress, imgname, size = img_size); /* Download single fw packets. */ do { if (img_size <= max_pkt_size) { last_pkt = 1; pkt_size = img_size; } progress_update(&progress, size - img_size); progress_draw(&progress); bzero(&cdb, sizeof(cdb)); if (strcmp(type, "scsi") == 0) { cdb.opcode = WRITE_BUFFER; cdb.control = 0; /* Parameter list length. */ scsi_ulto3b(pkt_size, &cdb.length[0]); offset = vp->inc_cdb_offset ? (pkt_ptr - buf) : 0; scsi_ulto3b(offset, &cdb.offset[0]); cdb.byte2 = last_pkt ? vp->cdb_byte2_last : vp->cdb_byte2; cdb.buffer_id = vp->inc_cdb_buffer_id ? pkt_count : 0; /* Zero out payload of ccb union after ccb header. */ bzero((u_char *)ccb + sizeof(struct ccb_hdr), sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); /* Copy previously constructed cdb into ccb_scsiio struct. */ bcopy(&cdb, &ccb->csio.cdb_io.cdb_bytes[0], sizeof(struct scsi_write_buffer)); /* Fill rest of ccb_scsiio struct. */ if (!sim_mode) { cam_fill_csio(&ccb->csio, /* ccb_scsiio */ retry_count, /* retries */ NULL, /* cbfcnp */ CAM_DIR_OUT | CAM_DEV_QFRZDIS, /* flags */ CAM_TAG_ACTION_NONE, /* tag_action */ (u_char *)pkt_ptr, /* data_ptr */ pkt_size, /* dxfer_len */ SSD_FULL_SIZE, /* sense_len */ sizeof(struct scsi_write_buffer), /* cdb_len */ timeout ? timeout : CMD_TIMEOUT); /* timeout */ } } else if (strcmp(type, "ata") == 0) { bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr)); if (!sim_mode) { uint32_t off; cam_fill_ataio(&ccb->ataio, (last_pkt) ? 256 : retry_count, NULL, /*flags*/CAM_DIR_OUT | CAM_DEV_QFRZDIS, CAM_TAG_ACTION_NONE, /*data_ptr*/(uint8_t *)pkt_ptr, /*dxfer_len*/pkt_size, timeout ? timeout : 30 * 1000); off = (uint32_t)(pkt_ptr - buf); ata_28bit_cmd(&ccb->ataio, ATA_DOWNLOAD_MICROCODE, USE_OFFSETS_FEATURE, ATA_MAKE_LBA(off, pkt_size), ATA_MAKE_SECTORS(pkt_size)); } } if (!sim_mode) { /* Execute the command. */ if (cam_send_ccb(cam_dev, ccb) < 0 || (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { warnx("Error writing image to device"); if (printerrors) cam_error_print(cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); goto bailout; } } /* Prepare next round. */ pkt_count++; pkt_ptr += pkt_size; img_size -= pkt_size; } while(!last_pkt); progress_complete(&progress, size - img_size); cam_freeccb(ccb); return (0); bailout: progress_complete(&progress, size - img_size); cam_freeccb(ccb); return (1); }
int smp_send_req(const struct smp_target_obj * tobj, struct smp_req_resp * rresp, int verbose) { union ccb *ccb; struct tobj_cam_t * tcp; int retval, emsk; int flags = 0; if ((NULL == tobj) || (0 == tobj->opened) || (NULL == tobj->vp)) { if (verbose) fprintf(stderr, "smp_send_req: nothing open??\n"); return -1; } if (I_CAM != tobj->interface_selector) { fprintf(stderr, "smp_send_req: unknown transport [%d]\n", tobj->interface_selector); return -1; } tcp = (struct tobj_cam_t *)tobj->vp; if (! (ccb = cam_getccb(tcp->cam_dev))) { fprintf(stderr, "cam_getccb: failed\n"); return -1; } // clear out structure, except for header that was filled in for us bzero(&(&ccb->ccb_h)[1], sizeof(union ccb) - sizeof(struct ccb_hdr)); flags |= CAM_DEV_QFRZDIS; /* CAM does not want request_len including CRC */ cam_fill_smpio(&ccb->smpio, /*retries*/ 2, /* guess */ /*cbfcnp*/ NULL, /*flags*/ flags, /*smp_request*/ rresp->request, /*smp_request_len*/ rresp->request_len - 4, /*smp_response*/ rresp->response, /*smp_response_len*/ rresp->max_response_len, /*timeout*/ 5000); /* milliseconds ? */ ccb->smpio.flags = SMP_FLAG_NONE; emsk = 0; if (((retval = cam_send_ccb(tcp->cam_dev, ccb)) < 0) || ((((emsk = (ccb->ccb_h.status & CAM_STATUS_MASK))) != CAM_REQ_CMP) && (emsk != CAM_SMP_STATUS_ERROR))) { cam_error_print(tcp->cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); cam_freeccb(ccb); return -1; } if (((emsk == CAM_REQ_CMP) || (emsk == CAM_SMP_STATUS_ERROR)) && (rresp->max_response_len > 0)) { if ((emsk == CAM_SMP_STATUS_ERROR) && (verbose > 3)) cam_error_print(tcp->cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); rresp->act_response_len = -1; cam_freeccb(ccb); return 0; } else { fprintf(stderr, "smp_send_req(cam): not sure how it got here\n"); cam_freeccb(ccb); return emsk ? emsk : -1; } }
/** Sends a SCSI command to the drive, receives reply and evaluates wether the command succeeded or shall be retried or finally failed. Returned SCSI errors shall not lead to a return value indicating failure. The callers get notified by c->error. An SCSI failure which leads not to a retry shall be notified via scsi_notify_error(). The Libburn_log_sg_commandS facility might be of help when problems with a drive have to be examined. It shall stay disabled for normal use. @return: 1 success , <=0 failure */ int sg_issue_command(struct burn_drive *d, struct command *c) { int done = 0; int err; union ccb *ccb; if (d->cam == NULL) { c->error = 0; return 0; } c->error = 0; ccb = cam_getccb(d->cam); cam_fill_csio(&ccb->csio, 1, /* retries */ NULL, /* cbfncp */ CAM_DEV_QFRZDIS, /* flags */ MSG_SIMPLE_Q_TAG, /* tag_action */ NULL, /* data_ptr */ 0, /* dxfer_len */ sizeof (ccb->csio.sense_data), /* sense_len */ 0, /* cdb_len */ 30*1000); /* timeout */ switch (c->dir) { case TO_DRIVE: ccb->csio.ccb_h.flags |= CAM_DIR_OUT; break; case FROM_DRIVE: ccb->csio.ccb_h.flags |= CAM_DIR_IN; break; case NO_TRANSFER: ccb->csio.ccb_h.flags |= CAM_DIR_NONE; break; } ccb->csio.cdb_len = c->oplen; memcpy(&ccb->csio.cdb_io.cdb_bytes, &c->opcode, c->oplen); if (c->page) { ccb->csio.data_ptr = c->page->data; if (c->dir == FROM_DRIVE) { ccb->csio.dxfer_len = BUFFER_SIZE; /* touch page so we can use valgrind */ memset(c->page->data, 0, BUFFER_SIZE); } else { /* ts A61115: removed a ssert() */ if(c->page->bytes <= 0) return 0; ccb->csio.dxfer_len = c->page->bytes; } } else { ccb->csio.data_ptr = NULL; ccb->csio.dxfer_len = 0; } do { memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data)); err = cam_send_ccb(d->cam, ccb); if (err == -1) { libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010c, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, "Failed to transfer command to drive", errno, 0); cam_freeccb(ccb); sg_close_drive(d); d->released = 1; d->busy = BURN_DRIVE_IDLE; c->error = 1; return -1; } /* XXX */ memcpy(c->sense, &ccb->csio.sense_data, ccb->csio.sense_len); if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if (!c->retry) { c->error = 1; cam_freeccb(ccb); return 1; } switch (scsi_error(d, c->sense, 0)) { case RETRY: done = 0; break; case FAIL: done = 1; c->error = 1; break; } } else { done = 1; } } while (!done); cam_freeccb(ccb); return 1; }
/* Executes SCSI command (or at least forwards it to lower layers). * Clears os_err field prior to active call (whose result may set it * again). */ int do_scsi_pt(struct sg_pt_base * vp, int device_fd, int time_secs, int verbose) { int fd = device_fd - FREEBSD_FDOFFSET; struct sg_pt_freebsd_scsi * ptp = &vp->impl; struct freebsd_dev_channel *fdchan; union ccb *ccb; int len, timout_ms; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; ptp->os_err = 0; if (ptp->in_err) { if (verbose) fprintf(sg_warnings_strm, "Replicated or unused set_scsi_pt...\n"); return SCSI_PT_DO_BAD_PARAMS; } if (NULL == ptp->cdb) { if (verbose) fprintf(sg_warnings_strm, "No command (cdb) given\n"); return SCSI_PT_DO_BAD_PARAMS; } if ((fd < 0) || (fd >= FREEBSD_MAXDEV)) { if (verbose) fprintf(sg_warnings_strm, "Bad file descriptor\n"); ptp->os_err = ENODEV; return -ptp->os_err; } fdchan = devicetable[fd]; if (NULL == fdchan) { if (verbose) fprintf(sg_warnings_strm, "File descriptor closed??\n"); ptp->os_err = ENODEV; return -ptp->os_err; } if (NULL == fdchan->cam_dev) { if (verbose) fprintf(sg_warnings_strm, "No open CAM device\n"); return SCSI_PT_DO_BAD_PARAMS; } if (! (ccb = cam_getccb(fdchan->cam_dev))) { if (verbose) fprintf(sg_warnings_strm, "cam_getccb: failed\n"); ptp->os_err = ENOMEM; return -ptp->os_err; } ptp->ccb = ccb; // clear out structure, except for header that was filled in for us bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); timout_ms = (time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT; cam_fill_csio(&ccb->csio, /* retries */ 1, /* cbfcnp */ NULL, /* flags */ ptp->dxfer_dir, /* tagaction */ MSG_SIMPLE_Q_TAG, /* dataptr */ ptp->dxferp, /* datalen */ ptp->dxfer_len, /* senselen */ ptp->sense_len, /* cdblen */ ptp->cdb_len, /* timeout (millisecs) */ timout_ms); memcpy(ccb->csio.cdb_io.cdb_bytes, ptp->cdb, ptp->cdb_len); if (cam_send_ccb(fdchan->cam_dev, ccb) < 0) { if (verbose) { warn("error sending SCSI ccb"); #if __FreeBSD_version > 500000 cam_error_print(fdchan->cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); #endif } cam_freeccb(ptp->ccb); ptp->ccb = NULL; ptp->os_err = EIO; return -ptp->os_err; } if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR)) { ptp->scsi_status = ccb->csio.scsi_status; ptp->resid = ccb->csio.resid; ptp->sense_resid = ccb->csio.sense_resid; if ((SAM_STAT_CHECK_CONDITION == ptp->scsi_status) || (SAM_STAT_COMMAND_TERMINATED == ptp->scsi_status)) { len = ptp->sense_len - ptp->sense_resid; if (len) memcpy(ptp->sense, &(ccb->csio.sense_data), len); } } else ptp->transport_err = 1; ptp->cam_dev = fdchan->cam_dev; // for error processing return 0; }
int scsiattrib(struct cam_device *device, int argc, char **argv, char *combinedopt, int retry_count, int timeout, int verbosemode, int err_recover) { union ccb *ccb = NULL; int attr_num = -1; #if 0 int num_attrs = 0; #endif int start_attr = 0; int cached_attr = 0; int read_service_action = -1; int read_attr = 0, write_attr = 0; int element_address = 0; int element_type = ELEMENT_TYPE_ALL; int partition = 0; int logical_volume = 0; char *endptr; uint8_t *data_buf = NULL; uint32_t dxfer_len = UINT16_MAX - 1; uint32_t valid_len; uint32_t output_format; STAILQ_HEAD(, scsi_attr_desc) write_attr_list; int error = 0; int c; ccb = cam_getccb(device); if (ccb == NULL) { warnx("%s: error allocating CCB", __func__); error = 1; goto bailout; } bzero(&(&ccb->ccb_h)[1], sizeof(union ccb) - sizeof(struct ccb_hdr)); STAILQ_INIT(&write_attr_list); /* * By default, when displaying attribute values, we trim out * non-ASCII characters in ASCII fields. We display all fields * (description, attribute number, attribute size, and readonly * status). We default to displaying raw text. * * XXX KDM need to port this to stable/10 and newer FreeBSD * versions that have iconv built in and can convert codesets. */ output_format = SCSI_ATTR_OUTPUT_NONASCII_TRIM | SCSI_ATTR_OUTPUT_FIELD_ALL | SCSI_ATTR_OUTPUT_TEXT_RAW; data_buf = malloc(dxfer_len); if (data_buf == NULL) { warn("%s: error allocating %u bytes", __func__, dxfer_len); error = 1; goto bailout; } while ((c = getopt(argc, argv, combinedopt)) != -1) { switch (c) { case 'a': attr_num = strtol(optarg, &endptr, 0); if (*endptr != '\0') { warnx("%s: invalid attribute number %s", __func__, optarg); error = 1; goto bailout; } start_attr = attr_num; break; case 'c': cached_attr = 1; break; case 'e': element_address = strtol(optarg, &endptr, 0); if (*endptr != '\0') { warnx("%s: invalid element address %s", __func__, optarg); error = 1; goto bailout; } break; case 'F': { scsi_nv_status status; scsi_attrib_output_flags new_outflags; int entry_num = 0; char *tmpstr; if (isdigit(optarg[0])) { output_format = strtoul(optarg, &endptr, 0); if (*endptr != '\0') { warnx("%s: invalid numeric output " "format argument %s", __func__, optarg); error = 1; goto bailout; } break; } new_outflags = SCSI_ATTR_OUTPUT_NONE; while ((tmpstr = strsep(&optarg, ",")) != NULL) { status = scsi_get_nv(output_format_map, sizeof(output_format_map) / sizeof(output_format_map[0]), tmpstr, &entry_num, SCSI_NV_FLAG_IG_CASE); if (status == SCSI_NV_FOUND) new_outflags |= output_format_map[entry_num].value; else { warnx("%s: %s format option %s", __func__, (status == SCSI_NV_AMBIGUOUS) ? "ambiguous" : "invalid", tmpstr); error = 1; goto bailout; } } output_format = new_outflags; break; } case 'p': partition = strtol(optarg, &endptr, 0); if (*endptr != '\0') { warnx("%s: invalid partition number %s", __func__, optarg); error = 1; goto bailout; } break; case 'r': { scsi_nv_status status; int entry_num = 0; status = scsi_get_nv(sa_map, sizeof(sa_map) / sizeof(sa_map[0]), optarg, &entry_num, SCSI_NV_FLAG_IG_CASE); if (status == SCSI_NV_FOUND) read_service_action = sa_map[entry_num].value; else { warnx("%s: %s %s option %s", __func__, (status == SCSI_NV_AMBIGUOUS) ? "ambiguous" : "invalid", "service action", optarg); error = 1; goto bailout; } read_attr = 1; break; } case 's': start_attr = strtol(optarg, &endptr, 0); if (*endptr != '\0') { warnx("%s: invalid starting attr argument %s", __func__, optarg); error = 1; goto bailout; } break; case 'T': { scsi_nv_status status; int entry_num = 0; status = scsi_get_nv(elem_type_map, sizeof(elem_type_map) / sizeof(elem_type_map[0]), optarg, &entry_num, SCSI_NV_FLAG_IG_CASE); if (status == SCSI_NV_FOUND) element_type = elem_type_map[entry_num].value; else { warnx("%s: %s %s option %s", __func__, (status == SCSI_NV_AMBIGUOUS) ? "ambiguous" : "invalid", "element type", optarg); error = 1; goto bailout; } break; } case 'w': warnx("%s: writing attributes is not implemented yet", __func__); error = 1; goto bailout; break; case 'V': logical_volume = strtol(optarg, &endptr, 0); if (*endptr != '\0') { warnx("%s: invalid logical volume argument %s", __func__, optarg); error = 1; goto bailout; } break; default: break; } } /* * Default to reading attributes */ if (((read_attr == 0) && (write_attr == 0)) || ((read_attr != 0) && (write_attr != 0))) { warnx("%s: Must specify either -r or -w", __func__); error = 1; goto bailout; } if (read_attr != 0) { scsi_read_attribute(&ccb->csio, /*retries*/ retry_count, /*cbfcnp*/ NULL, /*tag_action*/ MSG_SIMPLE_Q_TAG, /*service_action*/ read_service_action, /*element*/ element_address, /*elem_type*/ element_type, /*logical_volume*/ logical_volume, /*partition*/ partition, /*first_attribute*/ start_attr, /*cache*/ cached_attr, /*data_ptr*/ data_buf, /*length*/ dxfer_len, /*sense_len*/ SSD_FULL_SIZE, /*timeout*/ timeout ? timeout : 60000); #if 0 } else { #endif } ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; if (err_recover != 0) ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; if (cam_send_ccb(device, ccb) < 0) { warn("error sending %s ATTRIBUTE", (read_attr != 0) ? "READ" : "WRITE"); if (verbosemode != 0) { cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); } error = 1; goto bailout; } if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if (verbosemode != 0) { cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); } error = 1; goto bailout; } if (read_attr == 0) goto bailout; valid_len = dxfer_len - ccb->csio.resid; switch (read_service_action) { case SRA_SA_ATTR_VALUES: { uint32_t len_left, hdr_len, cur_len; struct scsi_read_attribute_values *hdr; struct scsi_mam_attribute_header *cur_id; char error_str[512]; uint8_t *cur_pos; struct sbuf *sb; hdr = (struct scsi_read_attribute_values *)data_buf; if (valid_len < sizeof(*hdr)) { fprintf(stdout, "No attributes returned.\n"); error = 0; goto bailout; } sb = sbuf_new_auto(); if (sb == NULL) { warn("%s: Unable to allocate sbuf", __func__); error = 1; goto bailout; } /* * XXX KDM grab more data if it is available. */ hdr_len = scsi_4btoul(hdr->length); for (len_left = MIN(valid_len, hdr_len), cur_pos = &hdr->attribute_0[0]; len_left > sizeof(*cur_id); len_left -= cur_len, cur_pos += cur_len) { int cur_attr_num; cur_id = (struct scsi_mam_attribute_header *)cur_pos; cur_len = scsi_2btoul(cur_id->length) + sizeof(*cur_id); cur_attr_num = scsi_2btoul(cur_id->id); if ((attr_num != -1) && (cur_attr_num != attr_num)) continue; error = scsi_attrib_sbuf(sb, cur_id, len_left, /*user_table*/ NULL, /*num_user_entries*/ 0, /*prefer_user_table*/ 0, output_format, error_str, sizeof(error_str)); if (error != 0) { warnx("%s: %s", __func__, error_str); sbuf_delete(sb); error = 1; goto bailout; } if (attr_num != -1) break; } sbuf_finish(sb); fprintf(stdout, "%s", sbuf_data(sb)); sbuf_delete(sb); break; } case SRA_SA_SUPPORTED_ATTRS: case SRA_SA_ATTR_LIST: { uint32_t len_left, hdr_len; struct scsi_attrib_list_header *hdr; struct scsi_attrib_table_entry *entry = NULL; const char *sa_name = "Supported Attributes"; const char *at_name = "Available Attributes"; int attr_id; uint8_t *cur_id; hdr = (struct scsi_attrib_list_header *)data_buf; if (valid_len < sizeof(*hdr)) { fprintf(stdout, "No %s\n", (read_service_action == SRA_SA_SUPPORTED_ATTRS)? sa_name : at_name); error = 0; goto bailout; } fprintf(stdout, "%s:\n", (read_service_action == SRA_SA_SUPPORTED_ATTRS) ? sa_name : at_name); hdr_len = scsi_4btoul(hdr->length); for (len_left = MIN(valid_len, hdr_len), cur_id = &hdr->first_attr_0[0]; len_left > 1; len_left -= sizeof(uint16_t), cur_id += sizeof(uint16_t)) { attr_id = scsi_2btoul(cur_id); if ((attr_num != -1) && (attr_id != attr_num)) continue; entry = scsi_get_attrib_entry(attr_id); fprintf(stdout, "0x%.4x", attr_id); if (entry == NULL) fprintf(stdout, "\n"); else fprintf(stdout, ": %s\n", entry->desc); if (attr_num != -1) break; } break; } case SRA_SA_PART_LIST: case SRA_SA_LOG_VOL_LIST: { struct scsi_attrib_lv_list *lv_list; const char *partition_name = "Partition"; const char *lv_name = "Logical Volume"; if (valid_len < sizeof(*lv_list)) { fprintf(stdout, "No %s list returned\n", (read_service_action == SRA_SA_PART_LIST) ? partition_name : lv_name); error = 0; goto bailout; } lv_list = (struct scsi_attrib_lv_list *)data_buf; fprintf(stdout, "First %s: %d\n", (read_service_action == SRA_SA_PART_LIST) ? partition_name : lv_name, lv_list->first_lv_number); fprintf(stdout, "Number of %ss: %d\n", (read_service_action == SRA_SA_PART_LIST) ? partition_name : lv_name, lv_list->num_logical_volumes); break; } default: break; } bailout: if (ccb != NULL) cam_freeccb(ccb); free(data_buf); return (error); }
int sg_issue_command(struct burn_drive *d, struct command *c) { int done = 0, err, sense_len = 0, ret, ignore_error, i; int cam_pass_err_recover = 0, key, asc, ascq, timeout_ms; union ccb *ccb; static FILE *fp = NULL; time_t start_time; mmc_function_spy(NULL, "sg_issue_command"); c->error = 0; memset(c->sense, 0, sizeof(c->sense)); if (d->cam == NULL) return 0; if (burn_sg_log_scsi & 1) { if (fp == NULL) { fp= fopen("/tmp/libburn_sg_command_log", "a"); fprintf(fp, "\n-----------------------------------------\n"); } } if (burn_sg_log_scsi & 3) scsi_log_cmd(c,fp,0); c->error = 0; if (c->timeout > 0) timeout_ms = c->timeout; else timeout_ms = 200000; ccb = cam_getccb(d->cam); cam_fill_csio(&ccb->csio, 1, /* retries */ NULL, /* cbfncp */ CAM_DEV_QFRZDIS, /* flags */ MSG_SIMPLE_Q_TAG, /* tag_action */ NULL, /* data_ptr */ 0, /* dxfer_len */ sizeof (ccb->csio.sense_data), /* sense_len */ 0, /* cdb_len */ timeout_ms); /* timeout */ switch (c->dir) { case TO_DRIVE: ccb->csio.ccb_h.flags |= CAM_DIR_OUT; break; case FROM_DRIVE: ccb->csio.ccb_h.flags |= CAM_DIR_IN; break; case NO_TRANSFER: ccb->csio.ccb_h.flags |= CAM_DIR_NONE; break; } #ifdef Libburn_for_freebsd_ahcI /* ts B00325 : Advise by Alexander Motin */ /* Runs well on 8-STABLE (23 Mar 2003) But on 8-RELEASE cam_send_ccb() returns non-zero with errno 6 on eject. Long lasting TEST UNIT READY cycles break with errno 16. */ #ifdef Libburn_ahci_style_for_alL { #else if (d->is_ahci > 0) { #endif ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; cam_pass_err_recover = 1; } #endif /* Libburn_for_freebsd_ahcI */ ccb->csio.cdb_len = c->oplen; memcpy(&ccb->csio.cdb_io.cdb_bytes, &c->opcode, c->oplen); if (c->page) { ccb->csio.data_ptr = c->page->data; if (c->dir == FROM_DRIVE) { /* ts A90430 : Ticket 148 , by jwehle : "On ... FreeBSD 6.4 which has a usb memory reader in addition to a ATAPI DVD burner sg_issue_command will hang while the SCSI bus is being scanned" */ if (c->dxfer_len >= 0) ccb->csio.dxfer_len = c->dxfer_len; else ccb->csio.dxfer_len = BUFFER_SIZE; /* touch page so we can use valgrind */ memset(c->page->data, 0, BUFFER_SIZE); } else { ccb->csio.dxfer_len = c->page->bytes; } } else { ccb->csio.data_ptr = NULL; ccb->csio.dxfer_len = 0; } start_time = time(NULL); for (i = 0; !done; i++) { memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data)); memset(c->sense, 0, sizeof(c->sense)); err = cam_send_ccb(d->cam, ccb); ignore_error = sense_len = 0; /* ts B00325 : CAM_AUTOSNS_VALID advised by Alexander Motin */ if (ccb->ccb_h.status & CAM_AUTOSNS_VALID) { /* ts B00110 */ /* Better curb sense_len */ sense_len = ccb->csio.sense_len; if (sense_len > (int) sizeof(c->sense)) sense_len = sizeof(c->sense); memcpy(c->sense, &ccb->csio.sense_data, sense_len); spc_decode_sense(c->sense, sense_len, &key, &asc, &ascq); if (sense_len >= 14 && cam_pass_err_recover && key) ignore_error = 1; } if (err == -1 && cam_pass_err_recover && ! ignore_error) { #ifdef Libburn_ahci_verbouS fprintf(stderr, "libburn_EXPERIMENTAL: errno = %d . cam_errbuf = '%s'\n", errno, cam_errbuf); #endif if (errno == ENXIO && c->opcode[0] != 0) { /* Operations on empty or ejected tray */ /* MEDIUM NOT PRESENT */ #ifdef Libburn_ahci_verbouS fprintf(stderr, "libburn_EXPERIMENTAL: Emulating [2,3A,00] MEDIUM NOT PRESENT\n"); #endif c->sense[0] = 0x70; /*Fixed format sense data*/ c->sense[2] = 0x02; c->sense[12] = 0x3A; c->sense[13] = 0x00; sense_len = 14; ignore_error = 1; } else if (c->opcode[0] == 0 && (errno == EBUSY || errno == ENXIO)) { /* Timeout of TEST UNIT READY loop */ /* Inquiries while tray is being loaded */ /*LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE*/ #ifdef Libburn_ahci_verbouS fprintf(stderr, "libburn_EXPERIMENTAL: Emulating [2,04,00] LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE\n"); #endif c->sense[0] = 0x70; /*Fixed format sense data*/ c->sense[2] = 0x02; c->sense[12] = 0x04; c->sense[13] = 0x00; sense_len = 14; ignore_error = 1; } else if (errno == EINVAL) { /* Inappropriate MODE SENSE */ /* INVALID FIELD IN CDB */ #ifdef Libburn_ahci_verbouS fprintf(stderr, "libburn_EXPERIMENTAL: Emulating [5,24,00] INVALID FIELD IN CDB\n"); #endif c->sense[0] = 0x70; /*Fixed format sense data*/ c->sense[2] = 0x05; c->sense[12] = 0x24; c->sense[13] = 0x00; sense_len = 14; ignore_error = 1; } } if (err == -1 && !ignore_error) { libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010c, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, "Failed to transfer command to drive", errno, 0); sg_close_drive(d); d->released = 1; d->busy = BURN_DRIVE_IDLE; c->error = 1; {ret = -1; goto ex;} } /* XXX */ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if (sense_len < 14) { /*LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE*/ #ifdef Libburn_ahci_verbouS fprintf(stderr, "libburn_EXPERIMENTAL: CAM_STATUS= %d .Emulating [2,04,00] LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE\n", (ccb->ccb_h.status & CAM_STATUS_MASK)); #endif c->sense[0] = 0x70; /*Fixed format sense data*/ c->sense[2] = 0x02; c->sense[12] = 0x04; c->sense[13] = 0x00; done = 1; } /* >>> Need own duration time measurement. Then remove bit1 from flag. */ done = scsi_eval_cmd_outcome(d, c, fp, c->sense, sense_len, 0, start_time, timeout_ms, i, 2 | !!ignore_error); if (d->cancel) done = 1; } else { done = 1; } } while (!done); ret = 1; ex:; cam_freeccb(ccb); return ret; } /* ts B00115 */ /* Return 1 if the given path leads to a regular file or a device that can be seeked, read and eventually written with 2 kB granularity. */ int burn_os_is_2k_seekrw(char *path, int flag) { struct stat stbuf; #ifdef Libburn_DIOCGMEDIASIZE_ISBLK int fd, ret; off_t add_size; #else char *spt; int i, e; #endif /* ! Libburn_DIOCGMEDIASIZE_ISBLK */ if (stat(path, &stbuf) == -1) return 0; if (S_ISREG(stbuf.st_mode)) return 1; if (!S_ISCHR(stbuf.st_mode)) return 0; #ifdef Libburn_DIOCGMEDIASIZE_ISBLK /* If it throws no error with DIOCGMEDIASIZE then it is a 'block device' */ fd = open(path, O_RDONLY); if (fd == -1) return 0; ret = ioctl(fd, DIOCGMEDIASIZE, &add_size); close(fd); return (ret != -1); #else /* Libburn_DIOCGMEDIASIZE_ISBLK */ spt = strrchr(path, '/'); if (spt == NULL) spt = path; else spt++; e = strlen(spt); for (i = strlen(spt) - 1; i > 0; i--) if (spt[i] >= '0' && spt[i] <= '9') e = i; if (strncmp(spt, "da", e) == 0) /* SCSI disk. E.g. USB stick. */ return 1; if (strncmp(spt, "cd", e) == 0) /* SCSI CD drive might be writeable. */ return 1; if (strncmp(spt, "ad", e) == 0) /* IDE hard drive */ return 1; if (strncmp(spt, "acd", e) == 0) /* IDE CD drive might be writeable */ return 1; if (strncmp(spt, "fd", e) == 0) /* Floppy disk */ return 1; if (strncmp(spt, "fla", e) == 0) /* Flash drive */ return 1; return 0; #endif /* ! Libburn_DIOCGMEDIASIZE_ISBLK */ } /* ts A70909 */ /** Estimate the potential payload capacity of a file address. @param path The address of the file to be examined. If it does not exist yet, then the directory will be inquired. @param bytes This value gets modified if an estimation is possible @return -2 = cannot perform necessary operations on file object -1 = neither path nor dirname of path exist 0 = could not estimate size capacity of file object 1 = estimation has been made, bytes was set */ int burn_os_stdio_capacity(char *path, off_t *bytes) { struct stat stbuf; struct statvfs vfsbuf; char *testpath = NULL, *cpt; off_t add_size = 0; int fd, ret; BURN_ALLOC_MEM(testpath, char, 4096); testpath[0] = 0; if (stat(path, &stbuf) == -1) { strcpy(testpath, path); cpt = strrchr(testpath, '/'); if(cpt == NULL) strcpy(testpath, "."); else if(cpt == testpath) testpath[1] = 0; else *cpt = 0; if (stat(testpath, &stbuf) == -1) {ret = -1; goto ex;} #ifdef Libburn_if_this_was_linuX } else if(S_ISBLK(stbuf.st_mode)) { int open_mode = O_RDWR, fd, ret; long blocks; blocks = *bytes / 512; if(burn_sg_open_o_excl) open_mode |= O_EXCL; fd = open(path, open_mode); if (fd == -1) {ret = -2; goto ex;} ret = ioctl(fd, BLKGETSIZE, &blocks); close(fd); if (ret == -1) {ret = -2; goto ex;} *bytes = ((off_t) blocks) * (off_t) 512; #endif /* Libburn_if_this_was_linuX */ } else if(S_ISCHR(stbuf.st_mode)) { fd = open(path, O_RDONLY); if (fd == -1) {ret = -2; goto ex;} ret = ioctl(fd, DIOCGMEDIASIZE, &add_size); close(fd); if (ret == -1) {ret = -2; goto ex;} *bytes = add_size; } else if(S_ISREG(stbuf.st_mode)) { add_size = stbuf.st_blocks * (off_t) 512; strcpy(testpath, path); } else {ret = 0; goto ex;} if (testpath[0]) { if (statvfs(testpath, &vfsbuf) == -1) {ret = -2; goto ex;} *bytes = add_size + ((off_t) vfsbuf.f_frsize) * (off_t) vfsbuf.f_bavail; } ret = 1; ex: BURN_FREE_MEM(testpath); return ret; } /* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */ #ifdef Libburn_read_o_direcT /* No special O_DIRECT-like precautions are implemented here */ #endif /* Libburn_read_o_direcT */ int burn_os_open_track_src(char *path, int open_flags, int flag) { int fd; fd = open(path, open_flags); return fd; }