Exemplo n.º 1
0
/*!
  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;
}
Exemplo n.º 2
0
Arquivo: fsm.c Projeto: 2asoft/freebsd
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;
}
Exemplo n.º 3
0
/* 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;
}
Exemplo n.º 4
0
/*---------------------------------------------------------------------------
 *
 *--------------------------------------------------------------------------*/
int 
send_scsi_command(char *buffer, scsi_command_t *s, int cmd_id) 
{
#ifdef DIXTRAC_LINUX_SG

  int cmd_len,status = 0;

#ifdef LINUX_SG_IO
  sg_io_hdr_t sgio_hdr;
#else
  uint in_size,out_size;
  struct sg_header *sg_hd;
  char *buf_pointer;
#endif

#ifndef SG_TIMER  
  struct timeval start;
  struct timezone tz;
#endif


#ifdef WRITE_CHECK
  assert((s->command.opcode!=WRITE_6) && (s->command.opcode!=WRITE_10));
#endif

  cmd_len = s->length;

  /* safety checks */
  if (!cmd_len) return -1;            /* need a cmd_len != 0 */
  if (!buffer) return -1;             /* check argument to be != NULL */

/*   printf("SCSI command 0x%2X: length %d, datalen %d\n",s->command.opcode, */
/* 	 s->length,s->datalen); */

#ifdef LINUX_SG_IO
  memset((void *) &sgio_hdr, 0, sizeof(sg_io_hdr_t));
  sgio_hdr.interface_id = 'S';
  sgio_hdr.cmd_len = cmd_len;
  sgio_hdr.iovec_count = 0;
  sgio_hdr.mx_sb_len = sizeof(sense_buffer);
  if (scsi_command_type (s->command.opcode) == SCSI_DATA_IN) 
    sgio_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
  else
    sgio_hdr.dxfer_direction = SG_DXFER_TO_DEV;
  sgio_hdr.dxfer_len = s->datalen;
  sgio_hdr.dxferp = (void *) buffer;
  sgio_hdr.cmdp = (unsigned char *) &(s->command);
  sgio_hdr.sbp = (unsigned char *) sense_buffer;
  sgio_hdr.timeout = SG_IO_TIMEOUT;
  sgio_hdr.pack_id = cmd_id;
  sgio_hdr.flags = SG_FLAG_DIRECT_IO; 
#else
  /* adjust pointer to buffer passed to write so that we can prepend the 
     data in buffer with the SCSI command                                */
  buf_pointer = buffer - cmd_len;
  /* copy the command */
  memcpy(buf_pointer,(char *) &s->command,s->length );
  
  if (scsi_command_type (s->command.opcode) == SCSI_DATA_IN) {
    in_size = 0;
    out_size = s->datalen;
  }
  else {
    in_size = s->datalen;
    out_size = 0;
    /* copy the additional data to be sent */
    /* memcpy(in_buffer + SCSI_OFFSET + s->length,buffer,in_size); */
  }
  /* make sure we are sending at most # of bytes handled by sg driver */
  if (SG_HDR_OFFSET + cmd_len + in_size > SG_BIG_BUFF) return -1;
 
  if (SG_HDR_OFFSET + out_size > SG_BIG_BUFF) {
    out_size = SG_BIG_BUFF-SG_HDR_OFFSET;
    /*
    printf("exec_scsi_command: Warning - can retrieve only %d KB of data\n",
	   out_size / 1024);
    */
  }
  /* make buf_pointer point to the begining of the buffer given to write */
  buf_pointer -= SG_HDR_OFFSET;

  /* generic SCSI device header construction */
  sg_hd = (struct sg_header *) buf_pointer;
  sg_hd->reply_len   = SG_HDR_OFFSET + out_size;
  sg_hd->twelve_byte = (cmd_len == 12);
  sg_hd->pack_id = cmd_id; 
  sg_hd->result = 0;
#endif

#ifndef SG_TIMER  
  gettimeofday(&start,&tz);
#endif

#ifdef LINUX_SG_IO
  /* send command */
#ifdef STATE_THREADS
  status = st_write(scsidev_fd, &sgio_hdr, sizeof(sg_io_hdr_t),ST_TIMEOUT);
#else
  status = write(scsidev_fd, &sgio_hdr, sizeof(sg_io_hdr_t));
#endif
  if ( status < 0 || (status < sizeof(sg_io_hdr_t))) {
    /* some error happened */
    fprintf( stderr, "write(sg_io) result = 0x%x cmd = 0x%x\n",
	     status, s->command.opcode );
  }
#else
  /* send command */
  status = write(scsidev_fd, buf_pointer, SG_HDR_OFFSET + cmd_len + in_size);
  if ( status < 0 || status != SG_HDR_OFFSET + cmd_len + in_size ||
       sg_hd->result ) {
    /* some error happened */
    fprintf( stderr, "write(generic) result = 0x%x cmd = 0x%x\n",
	     sg_hd->result, s->command.opcode );
  }
#endif

#ifdef SG_TIMER

  //  printf("%s() (%d,%d)\n", __func__, sgio_hdr.duration.tv_sec,
  //	 sgio_hdr.duration.tv_usec);

#ifdef LINUX_SG_IO
  ustart = sgio_hdr.duration.tv_usec;
  ustart_sec = sgio_hdr.duration.tv_sec;
#else
  ustart = sg_hd->time.tv_usec;
  ustart_sec = sg_hd->time.tv_sec;
#endif
#else 
  ustart = start.tv_usec;
  ustart_sec = start.tv_sec;
#endif  

  return status;

/* DIXTRAC_LINUX_SG */
#endif

#ifdef DIXTRAC_FREEBSD_CAM
  union ccb ccb;
  int flags;
  int rc;
  char cmd_spec[30];

  struct timeval start;
  struct timeval stop;
  struct timezone tz;
  
  flags = (scsi_command_type (s->command.opcode) == 
	   SCSI_DATA_IN) ? CAM_DIR_IN : CAM_DIR_OUT;

  ccb.ccb_h.path_id = cam_device.path_id;
  ccb.ccb_h.target_id = cam_device.target_id;
  ccb.ccb_h.target_lun = cam_device.target_lun;

  /* The following command must be included to make CAM work */
  sprintf(cmd_spec,"");
  for(rc=0;rc<s->length;rc++) {
    sprintf(cmd_spec,"%s v",cmd_spec);
  }

  csio_build(&ccb.csio,
	     /* data_ptr */ buffer,
	     /* dxfer_len */ s->datalen,
	     /* flags */ flags | CAM_DEV_QFRZDIS,
	     /* retry_count */ 0,
	     /* timeout */ 5000, 
	     /* cmd_spec...*/ cmd_spec, 
	     ((char *) &s->command)[0],((char *) &s->command)[1],
	     ((char *) &s->command)[2],((char *) &s->command)[3],
	     ((char *) &s->command)[4],((char *) &s->command)[5],
	     ((char *) &s->command)[6],((char *) &s->command)[7],
	     ((char *) &s->command)[8],((char *) &s->command)[9],
	     ((char *) &s->command)[10],((char *) &s->command)[11],
	     ((char *) &s->command)[12],((char *) &s->command)[13],
	     ((char *) &s->command)[14],((char *) &s->command)[15]
);

  gettimeofday(&start,&tz);
  ustart = start.tv_usec;
  ustart_sec = start.tv_sec;

  rc = cam_send_ccb(&cam_device, &ccb);

  gettimeofday(&stop,&tz);
  ustop_sec = stop.tv_sec;
  ustop = stop.tv_usec;

  if (rc < 0 || 
      (ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
    fprintf(stderr, "Error: cam_send_ccb (rc=%d)\n", rc);

    if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) {
      fprintf(stderr, "Printing sense buffer\n");
      scsi_sense_print(&cam_device, &ccb.csio, stderr);
    }
    return -1;
  }

  return 0;

/* DIXTRAC_FREEBSD_CAM */
#endif
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
/*
 * 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;
}
Exemplo n.º 7
0
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
}
Exemplo n.º 8
0
/* 
 * 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);
}
Exemplo n.º 9
0
/* 
 * 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);
}
Exemplo n.º 10
0
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;
    }
}
Exemplo n.º 11
0
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
}
Exemplo n.º 12
0
/** 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;
}
Exemplo n.º 13
0
/* 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;
}
Exemplo n.º 14
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);
}
Exemplo n.º 15
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;
}
Exemplo n.º 16
0
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;
}