void scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *), u_int tag_action, int readop, u_int byte2, u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len, u_int32_t timeout) { struct scsi_send_receive *scsi_cmd; scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes; scsi_cmd->opcode = readop ? RECEIVE : SEND; scsi_cmd->byte2 = byte2; scsi_ulto3b(xfer_len, scsi_cmd->xfer_len); scsi_cmd->control = 0; cam_fill_csio(csio, retries, cbfcnp, /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT, tag_action, data_ptr, xfer_len, sense_len, sizeof(*scsi_cmd), timeout); }
/*! Run a SCSI MMC command. p_user_data internal CD structure. i_timeout_ms time in milliseconds we will wait for the command to complete. If this value is -1, use the default time-out value. i_cdb Size of p_cdb p_cdb CDB bytes. e_direction direction the transfer is to go. i_buf Size of buffer p_buf Buffer for data, both sending and receiving Return 0 if no error. */ int run_mmc_cmd_freebsd_cam( const void *p_user_data, unsigned int i_timeout_ms, unsigned int i_cdb, const mmc_cdb_t *p_cdb, cdio_mmc_direction_t e_direction, unsigned int i_buf, /*in/out*/ void *p_buf ) { const _img_private_t *p_env = p_user_data; int i_status; int direction = CAM_DEV_QFRZDIS; union ccb ccb; if (!p_env || !p_env->cam) return -2; memset(&ccb, 0, sizeof(ccb)); ccb.ccb_h.path_id = p_env->cam->path_id; ccb.ccb_h.target_id = p_env->cam->target_id; ccb.ccb_h.target_lun = p_env->cam->target_lun; ccb.ccb_h.timeout = i_timeout_ms; if (!i_buf) direction |= CAM_DIR_NONE; else direction |= (e_direction == SCSI_MMC_DATA_READ)?CAM_DIR_IN : CAM_DIR_OUT; memcpy(ccb.csio.cdb_io.cdb_bytes, p_cdb->field, i_cdb); ccb.csio.cdb_len = mmc_get_cmd_len(ccb.csio.cdb_io.cdb_bytes[0]); cam_fill_csio (&(ccb.csio), 1, NULL, direction | CAM_DEV_QFRZDIS, MSG_SIMPLE_Q_TAG, p_buf, i_buf, sizeof(ccb.csio.sense_data), ccb.csio.cdb_len, 30*1000); if (cam_send_ccb(p_env->cam, &ccb) < 0) { cdio_warn ("transport failed: %s", strerror(errno)); return -1; } if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { return 0; } errno = EIO; i_status = ERRCODE(((unsigned char *)&ccb.csio.sense_data)); if (i_status == 0) i_status = -1; else CREAM_ON_ERRNO(((unsigned char *)&ccb.csio.sense_data)); cdio_warn ("transport failed: %d", i_status); return i_status; }
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; }
int scsi_cmd(int fd, unsigned char *cdb, int cmdlen, scsi_io_mode_t mode, void *data, size_t len, void *extra_data) { #if defined OS_hpux struct sctl_io sctl_io; memset(&sctl_io, 0, sizeof sctl_io); /* clear reserved fields */ memcpy(sctl_io.cdb, cdb, cmdlen); /* copy command */ sctl_io.cdb_length = cmdlen; /* command length */ sctl_io.max_msecs = 2000; /* allow 2 seconds for cmd */ switch (mode) { case SCSI_IO_READ: sctl_io.flags = SCTL_READ; sctl_io.data_length = len; sctl_io.data = data; break; case SCSI_IO_WRITE: sctl_io.flags = 0; sctl_io.data_length = data ? len : 0; sctl_io.data = len ? data : 0; break; } if (ioctl(fd, SIOC_IO, &sctl_io) == -1) { perror("scsi_io"); return -1; } return sctl_io.cdb_status; #elif defined OS_sunos || defined OS_solaris struct uscsi_cmd uscsi_cmd; memset(&uscsi_cmd, 0, sizeof uscsi_cmd); uscsi_cmd.uscsi_cdb = (char *)cdb; uscsi_cmd.uscsi_cdblen = cmdlen; #ifdef OS_solaris uscsi_cmd.uscsi_timeout = 20; /* msec? */ #endif /* solaris */ uscsi_cmd.uscsi_buflen = (u_int)len; uscsi_cmd.uscsi_bufaddr = data; switch (mode) { case SCSI_IO_READ: uscsi_cmd.uscsi_flags = USCSI_READ; break; case SCSI_IO_WRITE: uscsi_cmd.uscsi_flags = USCSI_WRITE; break; } if (ioctl(fd, USCSICMD, &uscsi_cmd) == -1) { perror("scsi_io"); return -1; } if(uscsi_cmd.uscsi_status) { errno = 0; fprintf(stderr,"scsi status=%x\n", (unsigned short)uscsi_cmd.uscsi_status); return -1; } return 0; #elif defined OS_linux struct sg_io_hdr my_scsi_cmd; /* ** Init the command */ memset(&scsi_cmd,0,sizeof(scsi_cmd)); my_scsi_cmd.interface_id = 'S'; my_scsi_cmd.dxfer_direction = (mode == SCSI_IO_READ)?(SG_DXFER_FROM_DEV):(SG_DXFER_TO_DEV); my_scsi_cmd.cmd_len = cmdlen; my_scsi_cmd.mx_sb_len = 0; my_scsi_cmd.dxfer_len = len; my_scsi_cmd.dxferp = data; my_scsi_cmd.cmdp = cdb; my_scsi_cmd.timeout = ~0; /* where is MAX_UINT defined??? */ #ifdef DEBUG printf("CMD(%d): %02x%02x%02x%02x%02x%02x %sdevice\n",cmdlen,cdb[0],cdb[1],cdb[2],cdb[3],cdb[4],cdb[5], (mode==SCSI_IO_READ)?("<-"):("->")); printf("DATA : len = %d\n",len); #endif if (ioctl(fd, SG_IO,&my_scsi_cmd) < 0) { perror("scsi_io"); return -1; } return my_scsi_cmd.status & STATUS_MASK; #elif (defined _SCO_DS) && (defined SCSIUSERCMD) struct scsicmd my_scsi_cmd; memset(my_scsi_cmd.cdb, 0, SCSICMDLEN); /* ensure zero pad */ memcpy(my_scsi_cmd.cdb, cdb, cmdlen); my_scsi_cmd.cdb_len = cmdlen; my_scsi_cmd.data_len = len; my_scsi_cmd.data_ptr = data; my_scsi_cmd.is_write = mode == SCSI_IO_WRITE; if (ioctl(fd,SCSIUSERCMD,&my_scsi_cmd) == -1) { perror("scsi_io: SCSIUSERCMD"); return -1; } if (my_scsi_cmd.host_sts != 0 || my_scsi_cmd.target_sts != 0) { fprintf(stderr, "scsi_io: scsi status: host=%x; target=%x\n", (unsigned)my_scsi_cmd.host_sts,(unsigned)my_scsi_cmd.target_sts); return -1; } return 0; #elif defined sgi struct dsreq my_scsi_cmd; my_scsi_cmd.ds_cmdbuf = (char *)cdb; my_scsi_cmd.ds_cmdlen = cmdlen; my_scsi_cmd.ds_databuf = data; my_scsi_cmd.ds_datalen = len; switch (mode) { case SCSI_IO_READ: my_scsi_cmd.ds_flags = DSRQ_READ|DSRQ_SENSE; break; case SCSI_IO_WRITE: my_scsi_cmd.ds_flags = DSRQ_WRITE|DSRQ_SENSE; break; } my_scsi_cmd.ds_time = 10000; my_scsi_cmd.ds_link = 0; my_scsi_cmd.ds_synch =0; my_scsi_cmd.ds_ret =0; if (ioctl(fd, DS_ENTER, &my_scsi_cmd) == -1) { perror("scsi_io"); return -1; } if(my_scsi_cmd.ds_status) { errno = 0; fprintf(stderr,"scsi status=%x\n", (unsigned short)my_scsi_cmd.ds_status); return -1; } return 0; #elif (defined OS_freebsd) && (__FreeBSD__ >= 2) #define MSG_SIMPLE_Q_TAG 0x20 /* O/O */ union ccb *ccb; int flags; int r; struct cam_device *cam_dev = (struct cam_device *) extra_data; if (cam_dev==NULL || cam_dev->fd!=fd) { fprintf(stderr,"invalid file descriptor\n"); return -1; } ccb = cam_getccb(cam_dev); bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cmdlen); if (mode == SCSI_IO_READ) flags = CAM_DIR_IN; else if (data && len) flags = CAM_DIR_OUT; else flags = CAM_DIR_NONE; cam_fill_csio(&ccb->csio, /* retry */ 1, /* cbfcnp */ NULL, flags, /* tag_action */ MSG_SIMPLE_Q_TAG, /*data_ptr*/ len ? data : 0, /*data_len */ data ? len : 0, 96, cmdlen, 5000); if (cam_send_ccb(cam_dev, ccb) < 0 || (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { return -1; } return 0; #elif defined(OS_netbsd) || defined(OS_netbsdelf) struct scsireq sc; memset(&sc, 0, sizeof(sc)); memcpy(sc.cmd, cdb, cmdlen); sc.cmdlen = cmdlen; sc.databuf = data; sc.datalen = len; sc.senselen = 0; sc.timeout = 10000; switch (mode) { case SCSI_IO_READ: sc.flags = SCCMD_READ; break; case SCSI_IO_WRITE: sc.flags = SCCMD_WRITE; break; } if (ioctl(fd, SCIOCCOMMAND, &sc) == -1) { perror("SCIOCCOMMAND ioctl"); return -1; } if (sc.retsts) { errno = EIO; fprintf(stderr, "SCSI command failed, retsts %d\n", sc.retsts); return -1; } return 0; #else fprintf(stderr, "scsi_io not implemented\n"); return -1; #endif }
/* * 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_getccb(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 */ (u_int8_t *)cmd_page, /* dataptr */ cmd_page_len, /* datalen */ sizeof(sense), /* senselength */ cdb_len, /* cdblength */ 15000 /* timeout (millisecs) */); memcpy(ccb->csio.cdb_io.cdb_bytes, cdb, cdb_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); }
int scsi_cmd(int fd, unsigned char *cdb, int cmdlen, scsi_io_mode_t mode, void *data, size_t len, void *extra_data) { #if defined OS_hpux struct sctl_io sctl_io; memset(&sctl_io, 0, sizeof sctl_io); /* clear reserved fields */ memcpy(sctl_io.cdb, cdb, cmdlen); /* copy command */ sctl_io.cdb_length = cmdlen; /* command length */ sctl_io.max_msecs = 2000; /* allow 2 seconds for cmd */ switch (mode) { case SCSI_IO_READ: sctl_io.flags = SCTL_READ; sctl_io.data_length = len; sctl_io.data = data; break; case SCSI_IO_WRITE: sctl_io.flags = 0; sctl_io.data_length = data ? len : 0; sctl_io.data = len ? data : 0; break; } if (ioctl(fd, SIOC_IO, &sctl_io) == -1) { perror("scsi_io"); return -1; } return sctl_io.cdb_status; #elif defined OS_sunos || defined OS_solaris struct uscsi_cmd uscsi_cmd; memset(&uscsi_cmd, 0, sizeof uscsi_cmd); uscsi_cmd.uscsi_cdb = (char *)cdb; uscsi_cmd.uscsi_cdblen = cmdlen; #ifdef OS_solaris uscsi_cmd.uscsi_timeout = 20; /* msec? */ #endif /* solaris */ uscsi_cmd.uscsi_buflen = (u_int)len; uscsi_cmd.uscsi_bufaddr = data; switch (mode) { case SCSI_IO_READ: uscsi_cmd.uscsi_flags = USCSI_READ; break; case SCSI_IO_WRITE: uscsi_cmd.uscsi_flags = USCSI_WRITE; break; } if (ioctl(fd, USCSICMD, &uscsi_cmd) == -1) { perror("scsi_io"); return -1; } if(uscsi_cmd.uscsi_status) { errno = 0; fprintf(stderr,"scsi status=%x\n", (unsigned short)uscsi_cmd.uscsi_status); return -1; } return 0; #elif defined OS_linux struct scsi_ioctl_command scsi_cmd; memcpy(scsi_cmd.cmd, cdb, cmdlen); /* copy command */ switch (mode) { case SCSI_IO_READ: scsi_cmd.inlen = 0; scsi_cmd.outlen = len; break; case SCSI_IO_WRITE: scsi_cmd.inlen = len; scsi_cmd.outlen = 0; memcpy(scsi_cmd.cmd + cmdlen,data,len); break; } if (ioctl(fd, SCSI_IOCTL_SEND_COMMAND, &scsi_cmd) < 0) { perror("scsi_io"); return -1; } switch (mode) { case SCSI_IO_READ: memcpy(data, &scsi_cmd.cmd[0], len); break; case SCSI_IO_WRITE: break; } return 0; /* where to get scsi status? */ #elif defined _SCO_DS struct scsicmd scsi_cmd; memset(scsi_cmd.cdb, 0, SCSICMDLEN); /* ensure zero pad */ memcpy(scsi_cmd.cdb, cdb, cmdlen); scsi_cmd.cdb_len = cmdlen; scsi_cmd.data_len = len; scsi_cmd.data_ptr = data; scsi_cmd.is_write = mode == SCSI_IO_WRITE; if (ioctl(fd,SCSIUSERCMD,&scsi_cmd) == -1) { perror("scsi_io"); printf("scsi status: host=%x; target=%x\n", (unsigned)scsi_cmd.host_sts,(unsigned)scsi_cmd.target_sts); return -1; } return 0; #elif defined sgi struct dsreq scsi_cmd; scsi_cmd.ds_cmdbuf = (char *)cdb; scsi_cmd.ds_cmdlen = cmdlen; scsi_cmd.ds_databuf = data; scsi_cmd.ds_datalen = len; switch (mode) { case SCSI_IO_READ: scsi_cmd.ds_flags = DSRQ_READ|DSRQ_SENSE; break; case SCSI_IO_WRITE: scsi_cmd.ds_flags = DSRQ_WRITE|DSRQ_SENSE; break; } scsi_cmd.ds_time = 10000; scsi_cmd.ds_link = 0; scsi_cmd.ds_synch =0; scsi_cmd.ds_ret =0; if (ioctl(fd, DS_ENTER, &scsi_cmd) == -1) { perror("scsi_io"); return -1; } if(scsi_cmd.ds_status) { errno = 0; fprintf(stderr,"scsi status=%x\n", (unsigned short)scsi_cmd.ds_status); return -1; } return 0; #elif (defined OS_freebsd) && (__FreeBSD__ >= 2) #define MSG_SIMPLE_Q_TAG 0x20 /* O/O */ union ccb *ccb; int flags; int r; struct cam_device *cam_dev = (struct cam_device *) extra_data; if (cam_dev==NULL || cam_dev->fd!=fd) { fprintf(stderr,"invalid file descriptor\n"); return -1; } ccb = cam_getccb(cam_dev); bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cmdlen); if (mode == SCSI_IO_READ) flags = CAM_DIR_IN; else if (data && len) flags = CAM_DIR_OUT; else flags = CAM_DIR_NONE; cam_fill_csio(&ccb->csio, /* retry */ 1, /* cbfcnp */ NULL, flags, /* tag_action */ MSG_SIMPLE_Q_TAG, /*data_ptr*/ len ? data : 0, /*data_len */ data ? len : 0, 96, cmdlen, 5000); if (cam_send_ccb(cam_dev, ccb) < 0 || (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { return -1; } return 0; #else fprintf(stderr, "scsi_io not implemented\n"); return -1; #endif }
/* * 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); }
/** 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 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; }
boolean hfp_cdrom_send_ccb (HFPCDROM *cdrom, const char *ccb, int ccb_len, HFPCDROMDirection direction, void *data, int len, char **err) { int timeout; assert(cdrom != NULL); assert(ccb != NULL); assert(direction == HFP_CDROM_DIRECTION_NONE || direction == HFP_CDROM_DIRECTION_IN || direction == HFP_CDROM_DIRECTION_OUT); assert(direction == HFP_CDROM_DIRECTION_NONE || data != NULL); timeout = 10; if (cdrom->fd >= 0) /* ATAPI transport */ { #ifdef IOCATAREQUEST struct ata_ioc_request req; memset(&req, 0, sizeof(req)); req.flags = ATA_CMD_ATAPI; req.timeout = timeout; memcpy(req.u.atapi.ccb, ccb, 16); if (data) { static int atapi_direction[] = { 0, ATA_CMD_READ, ATA_CMD_WRITE }; req.flags |= atapi_direction[direction]; req.data = data; req.count = len; } if (ioctl(cdrom->fd, IOCATAREQUEST, &req) < 0) { if (err) *err = hfp_strdup_printf("IOCATAREQUEST failure: %s", strerror(errno)); return FALSE; } if (req.error != 0) { if (err) *err = hfp_strdup_printf("ATAPI error %i", req.error); return FALSE; } #else struct ata_cmd iocmd; /* Better to assert here than panic the machine. */ /* XXX Should this be a conditional? How likely is this? */ assert(cdrom->channel >= 0); assert(cdrom->device >= 0 && cdrom->device < 2); memset(&iocmd, 0, sizeof(iocmd)); iocmd.u.request.flags = ATA_CMD_ATAPI; iocmd.u.request.timeout = timeout; iocmd.cmd = ATAREQUEST; iocmd.channel = cdrom->channel; iocmd.device = cdrom->device; memcpy(iocmd.u.request.u.atapi.ccb, ccb, 16); if (data) { static int atapi_direction[] = { 0, ATA_CMD_READ, ATA_CMD_WRITE }; iocmd.u.request.flags |= atapi_direction[direction]; iocmd.u.request.data = data; iocmd.u.request.count = len; } if (ioctl(cdrom->fd, IOCATA, &iocmd) < 0) { if (err) *err = hfp_strdup_printf("IOCATA failure: %s", strerror(errno)); return FALSE; } if (iocmd.u.request.error != 0) { if (err) *err = hfp_strdup_printf("ATAPI error %i", iocmd.u.request.error); return FALSE; } #endif } else /* SCSI transport */ { union ccb cam_ccb; static int scsi_direction[] = { CAM_DIR_NONE, CAM_DIR_IN, CAM_DIR_OUT }; memset(&cam_ccb, 0, sizeof(cam_ccb)); cam_ccb.ccb_h.path_id = cdrom->cam->path_id; cam_ccb.ccb_h.target_id = cdrom->cam->target_id; cam_ccb.ccb_h.target_lun = cdrom->cam->target_lun; cam_fill_csio(&cam_ccb.csio, 1, NULL, scsi_direction[direction], MSG_SIMPLE_Q_TAG, data, len, sizeof(cam_ccb.csio.sense_data), ccb_len, timeout * 1000); memcpy(cam_ccb.csio.cdb_io.cdb_bytes, ccb, 16); if (cam_send_ccb(cdrom->cam, &cam_ccb) == -1) { if (err) *err = hfp_strdup_printf("cam_send_ccb() failure: %s", strerror(errno)); } if ((cam_ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if (err) *err = hfp_strdup_printf("CCB request failed with status %i", cam_ccb.ccb_h.status & CAM_STATUS_MASK); return FALSE; } } return TRUE; }
DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir, void *pvBuf, uint32_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies) { /* * Minimal input validation. */ Assert(enmTxDir == PDMMEDIATXDIR_NONE || enmTxDir == PDMMEDIATXDIR_FROM_DEVICE || enmTxDir == PDMMEDIATXDIR_TO_DEVICE); Assert(!pvBuf || pcbBuf); Assert(pvBuf || enmTxDir == PDMMEDIATXDIR_NONE); Assert(pbSense || !cbSense); AssertPtr(pbCmd); Assert(cbCmd <= 16 && cbCmd >= 1); const uint32_t cbBuf = pcbBuf ? *pcbBuf : 0; if (pcbBuf) *pcbBuf = 0; int rc = VINF_SUCCESS; int rcBSD = 0; union ccb DeviceCCB; union ccb *pDeviceCCB = &DeviceCCB; u_int32_t fFlags; memset(pDeviceCCB, 0, sizeof(DeviceCCB)); pDeviceCCB->ccb_h.path_id = pThis->Os.ScsiBus; pDeviceCCB->ccb_h.target_id = pThis->Os.ScsiTargetID; pDeviceCCB->ccb_h.target_lun = pThis->Os.ScsiLunID; /* The SCSI INQUIRY command can't be passed through directly. */ if (pbCmd[0] == SCSI_INQUIRY) { pDeviceCCB->ccb_h.func_code = XPT_GDEV_TYPE; rcBSD = ioctl(RTFileToNative(pThis->Os.hFileDevice), CAMIOCOMMAND, pDeviceCCB); if (!rcBSD) { uint32_t cbCopy = cbBuf < sizeof(struct scsi_inquiry_data) ? cbBuf : sizeof(struct scsi_inquiry_data);; memcpy(pvBuf, &pDeviceCCB->cgd.inq_data, cbCopy); memset(pbSense, 0, cbSense); if (pcbBuf) *pcbBuf = cbCopy; } else rc = RTErrConvertFromErrno(errno); } else { /* Copy the CDB. */ memcpy(&pDeviceCCB->csio.cdb_io.cdb_bytes, pbCmd, cbCmd); /* Set direction. */ if (enmTxDir == PDMMEDIATXDIR_NONE) fFlags = CAM_DIR_NONE; else if (enmTxDir == PDMMEDIATXDIR_FROM_DEVICE) fFlags = CAM_DIR_IN; else fFlags = CAM_DIR_OUT; fFlags |= CAM_DEV_QFRZDIS; cam_fill_csio(&pDeviceCCB->csio, 1, NULL, fFlags, MSG_SIMPLE_Q_TAG, (u_int8_t *)pvBuf, cbBuf, cbSense, cbCmd, cTimeoutMillies ? cTimeoutMillies : 30000/* timeout */); /* Send command */ rcBSD = ioctl(RTFileToNative(pThis->Os.hFileDevice), CAMIOCOMMAND, pDeviceCCB); if (!rcBSD) { switch (pDeviceCCB->ccb_h.status & CAM_STATUS_MASK) { case CAM_REQ_CMP: rc = VINF_SUCCESS; break; case CAM_SEL_TIMEOUT: rc = VERR_DEV_IO_ERROR; break; case CAM_CMD_TIMEOUT: rc = VERR_TIMEOUT; break; default: rc = VERR_DEV_IO_ERROR; } if (pcbBuf) *pcbBuf = cbBuf - pDeviceCCB->csio.resid; if (pbSense) memcpy(pbSense, &pDeviceCCB->csio.sense_data, cbSense - pDeviceCCB->csio.sense_resid); } else rc = RTErrConvertFromErrno(errno); } }