Esempio n. 1
0
static void
ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
{
	struct cam_periph *periph;

	periph = (struct cam_periph *)callback_arg;
	switch (code) {
	case AC_FOUND_DEVICE:
	{
		struct ccb_getdev *cgd;
		cam_status status;
 
		cgd = (struct ccb_getdev *)arg;
		if (cgd == NULL)
			break;

		if (cgd->protocol != PROTO_SCSI)
			break;

		if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
			break;

		/*
		 * Allocate a peripheral instance for
		 * this device and start the probe
		 * process.
		 */
		status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
					  ptstart, "pt", CAM_PERIPH_BIO,
					  cgd->ccb_h.path, ptasync,
					  AC_FOUND_DEVICE, cgd);

		if (status != CAM_REQ_CMP
		 && status != CAM_REQ_INPROG)
			printf("ptasync: Unable to attach to new device "
				"due to status 0x%x\n", status);
		break;
	}
	case AC_SENT_BDR:
	case AC_BUS_RESET:
	{
		struct pt_softc *softc;
		struct ccb_hdr *ccbh;

		softc = (struct pt_softc *)periph->softc;
		/*
		 * Don't fail on the expected unit attention
		 * that will occur.
		 */
		softc->flags |= PT_FLAG_RETRY_UA;
		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
			ccbh->ccb_state |= PT_CCB_RETRY_UA;
	}
	/* FALLTHROUGH */
	default:
		cam_periph_async(periph, code, path, arg);
		break;
	}
}
Esempio n. 2
0
/********************************************************************************
 * Handle completion of a command submitted via CAM.
 * Completion for extended cdb
 */
static void
amr_cam_complete_extcdb(struct amr_command *ac)
{
    struct amr_ext_passthrough      *aep = (struct amr_ext_passthrough *)ac->ac_data;
    struct ccb_scsiio           *csio = (struct ccb_scsiio *)ac->ac_private;
    struct scsi_inquiry_data    *inq = (struct scsi_inquiry_data *)csio->data_ptr;

    /* XXX note that we're ignoring ac->ac_status - good idea? */

    debug(1, "status 0x%x  scsi_status 0x%x", ac->ac_status, aep->ap_scsi_status);

    /*
     * Hide disks from CAM so that they're not picked up and treated as 'normal' disks.
     *
     * If the configuration provides a mechanism to mark a disk a "not managed", we
     * could add handling for that to allow disks to be selectively visible.
     */

    if ((aep->ap_cdb[0] == INQUIRY) && (SID_TYPE(inq) == T_DIRECT)) {
	bzero(csio->data_ptr, csio->dxfer_len);
	if (aep->ap_scsi_status == 0xf0) {
	    csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
	} else {
	    csio->ccb_h.status = CAM_DEV_NOT_THERE;
	}
    } else {

	/* handle passthrough SCSI status */
	switch(aep->ap_scsi_status) {
	case 0:				/* completed OK */
	    csio->ccb_h.status = CAM_REQ_CMP;
	    break;

	case 0x02:
	    csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
	    csio->scsi_status = SCSI_STATUS_CHECK_COND;
	    bcopy(aep->ap_request_sense_area, &csio->sense_data, AMR_MAX_REQ_SENSE_LEN);
	    csio->sense_len = AMR_MAX_REQ_SENSE_LEN;
	    csio->ccb_h.status |= CAM_AUTOSNS_VALID;
	    break;

	case 0x08:
	    csio->ccb_h.status = CAM_SCSI_BUSY;
	    break;

	case 0xf0:
	case 0xf4:
	default:
	    csio->ccb_h.status = CAM_REQ_CMP_ERR;
	    break;
	}
    }
    free(aep, M_DEVBUF);
    if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
	debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr, " ");
    xpt_done((union ccb *)csio);
    amr_releasecmd(ac);
}
Esempio n. 3
0
static cam_status
ptctor(struct cam_periph *periph, void *arg)
{
	struct pt_softc *softc;
	struct ccb_getdev *cgd;

	cgd = (struct ccb_getdev *)arg;
	if (periph == NULL) {
		kprintf("ptregister: periph was NULL!!\n");
		return(CAM_REQ_CMP_ERR);
	}

	if (cgd == NULL) {
		kprintf("ptregister: no getdev CCB, can't register device\n");
		return(CAM_REQ_CMP_ERR);
	}

	softc = kmalloc(sizeof(*softc), M_DEVBUF, M_INTWAIT | M_ZERO);
	LIST_INIT(&softc->pending_ccbs);
	softc->state = PT_STATE_NORMAL;
	bioq_init(&softc->bio_queue);

	softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;

	periph->softc = softc;
	
	cam_periph_unlock(periph);
	cam_extend_set(ptperiphs, periph->unit_number, periph);

	devstat_add_entry(&softc->device_stats, "pt",
			  periph->unit_number, 0,
			  DEVSTAT_NO_BLOCKSIZE,
			  SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
			  DEVSTAT_PRIORITY_OTHER);

	make_dev(&pt_ops, periph->unit_number, UID_ROOT,
		  GID_OPERATOR, 0600, "%s%d", periph->periph_name,
		  periph->unit_number);
	cam_periph_lock(periph);
	/*
	 * Add async callbacks for bus reset and
	 * bus device reset calls.  I don't bother
	 * checking if this fails as, in most cases,
	 * the system will function just fine without
	 * them and the only alternative would be to
	 * not attach the device on failure.
	 */
	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
			   ptasync, periph, periph->path);

	/* Tell the user we've attached to the device */
	xpt_announce_periph(periph, NULL);

	return(CAM_REQ_CMP);
}
Esempio n. 4
0
/*
 * Open a given device.  The path argument isn't strictly necessary, but it
 * is copied into the cam_device structure as a convenience to the user.
 */
static struct cam_device *
cam_real_open_device(const char *path, int flags, struct cam_device *device,
		     const char *given_path, const char *given_dev_name,
		     int given_unit_number)
{
	char *func_name = "cam_real_open_device";
	union ccb ccb;
	int fd = -1, malloced_device = 0;

	/*
	 * See if the user wants us to malloc a device for him.
	 */
	if (device == NULL) {
		if ((device = (struct cam_device *)malloc(
		     sizeof(struct cam_device))) == NULL) {
			snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
				 "%s: device structure malloc"
				 " failed\n%s: %s", func_name, func_name,
				 strerror(errno));
			return(NULL);
		}
		device->fd = -1;
		malloced_device = 1;
	} 

	/*
	 * If the user passed in a path, save it for him.
	 */
	if (given_path != NULL)
		strlcpy(device->device_path, given_path,
			sizeof(device->device_path));
	else
		device->device_path[0] = '\0';

	/*
	 * If the user passed in a device name and unit number pair, save
	 * those as well.
	 */
	if (given_dev_name != NULL)
		strlcpy(device->given_dev_name, given_dev_name,
			sizeof(device->given_dev_name));
	else
		device->given_dev_name[0] = '\0';
	device->given_unit_number = given_unit_number;

	if ((fd = open(path, flags)) < 0) {
		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
			 "%s: couldn't open passthrough device %s\n"
			 "%s: %s", func_name, path, func_name,
			 strerror(errno));
		goto crod_bailout;
	}

	device->fd = fd;

	bzero(&ccb, sizeof(union ccb));

	/*
	 * Unlike the transport layer version of the GETPASSTHRU ioctl,
	 * we don't have to set any fields.
	 */
	ccb.ccb_h.func_code = XPT_GDEVLIST;
	
	/*
	 * We're only doing this to get some information on the device in
	 * question.  Otherwise, we'd have to pass in yet another
	 * parameter: the passthrough driver unit number.
	 */
	if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
		/*
		 * At this point we know the passthrough device must exist
		 * because we just opened it above.  The only way this
		 * ioctl can fail is if the ccb size is wrong.
		 */
		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
			 "%s: CAMGETPASSTHRU ioctl failed\n"
			 "%s: %s", func_name, func_name, strerror(errno));
		goto crod_bailout;
	}

	/*
	 * If the ioctl returned the right status, but we got an error back
	 * in the ccb, that means that the kernel found the device the user
	 * passed in, but was unable to find the passthrough device for
	 * the device the user gave us.
	 */
	if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) {
		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
			 "%s: passthrough device does not exist!", func_name);
		goto crod_bailout;
	}

	device->dev_unit_num = ccb.cgdl.unit_number;
	strlcpy(device->device_name, ccb.cgdl.periph_name,
		sizeof(device->device_name));
	device->path_id = ccb.ccb_h.path_id;
	device->target_id = ccb.ccb_h.target_id;
	device->target_lun = ccb.ccb_h.target_lun;

	ccb.ccb_h.func_code = XPT_PATH_INQ;
	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
			 "%s: Path Inquiry CCB failed\n"
			 "%s: %s", func_name, func_name, strerror(errno));
		goto crod_bailout;
	}
	strlcpy(device->sim_name, ccb.cpi.dev_name, sizeof(device->sim_name));
	device->sim_unit_number = ccb.cpi.unit_number;
	device->bus_id = ccb.cpi.bus_id;

	/*
	 * It doesn't really matter what is in the payload for a getdev
	 * CCB, the kernel doesn't look at it.
	 */
	ccb.ccb_h.func_code = XPT_GDEV_TYPE;
	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
			 "%s: Get Device Type CCB failed\n"
			 "%s: %s", func_name, func_name, strerror(errno));
		goto crod_bailout;
	}
	device->pd_type = SID_TYPE(&ccb.cgd.inq_data);
	bcopy(&ccb.cgd.inq_data, &device->inq_data, 
	      sizeof(struct scsi_inquiry_data));
	device->serial_num_len = ccb.cgd.serial_num_len;
	bcopy(&ccb.cgd.serial_num, &device->serial_num, device->serial_num_len);

	/*
	 * Zero the payload, the kernel does look at the flags.
	 */
	bzero(&(&ccb.ccb_h)[1], sizeof(struct ccb_trans_settings));

	/*
	 * Get transfer settings for this device.
	 */
	ccb.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;

	ccb.cts.type = CTS_TYPE_CURRENT_SETTINGS;

	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
			 "%s: Get Transfer Settings CCB failed\n"
			 "%s: %s", func_name, func_name, strerror(errno));
		goto crod_bailout;
	}
	if (ccb.cts.transport == XPORT_SPI) {
		struct ccb_trans_settings_spi *spi =
		    &ccb.cts.xport_specific.spi;
		device->sync_period = spi->sync_period;
		device->sync_offset = spi->sync_offset;
		device->bus_width = spi->bus_width;
	} else {
		device->sync_period = 0;
		device->sync_offset = 0;
		device->bus_width = 0;
	}

	return(device);

crod_bailout:

	if (fd >= 0)
		close(fd);

	if (malloced_device)
		free(device);

	return(NULL);
}
Esempio n. 5
0
 /**********************************************************************
 * Handle completion of a command submitted via CAM.
 */
static void
amr_cam_complete(struct amr_command *ac)
{
	struct amr_passthrough		*ap;
	struct amr_ext_passthrough	*aep;
	struct ccb_scsiio		*csio;
	struct scsi_inquiry_data	*inq;
	int				scsi_status, cdb0;

	ap = &ac->ac_ccb->ccb_pthru;
	aep = &ac->ac_ccb->ccb_epthru;
	csio = (struct ccb_scsiio *)ac->ac_private;
	inq = (struct scsi_inquiry_data *)csio->data_ptr;

	if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
		scsi_status = aep->ap_scsi_status;
	else
		scsi_status = ap->ap_scsi_status;
	debug(1, "status 0x%x  AP scsi_status 0x%x", ac->ac_status,
	    scsi_status);

	/* Make sure the status is sane */
	if ((ac->ac_status != AMR_STATUS_SUCCESS) && (scsi_status == 0)) {
		csio->ccb_h.status = CAM_REQ_CMP_ERR;
		goto out;
	}

	/*
	 * Hide disks from CAM so that they're not picked up and treated as
	 * 'normal' disks.
	 *
	 * If the configuration provides a mechanism to mark a disk a "not
	 * managed", we could add handling for that to allow disks to be
	 * selectively visible.
	 */

	/* handle passthrough SCSI status */
	switch(scsi_status) {
	case 0:	/* completed OK */
		if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
			cdb0 = aep->ap_cdb[0];
		else
			cdb0 = ap->ap_cdb[0];
		if ((cdb0 == INQUIRY) && (SID_TYPE(inq) == T_DIRECT))
			inq->device = (inq->device & 0xe0) | T_NODEVICE;
		csio->ccb_h.status = CAM_REQ_CMP;
		break;

	case 0x02:
		csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
		csio->scsi_status = SCSI_STATUS_CHECK_COND;
		if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
			bcopy(aep->ap_request_sense_area, &csio->sense_data,
			    AMR_MAX_REQ_SENSE_LEN);
		else
			bcopy(ap->ap_request_sense_area, &csio->sense_data,
			    AMR_MAX_REQ_SENSE_LEN);
		csio->sense_len = AMR_MAX_REQ_SENSE_LEN;
		csio->ccb_h.status |= CAM_AUTOSNS_VALID;
		break;

	case 0x08:
		csio->ccb_h.status = CAM_SCSI_BUSY;
		break;

	case 0xf0:
	case 0xf4:
	default:
		/*
		 * Non-zero LUNs are already filtered, so there's no need
		 * to return CAM_DEV_NOT_THERE.
		 */
		csio->ccb_h.status = CAM_SEL_TIMEOUT;
		break;
	}

out:
	if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
		debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr,
		    " ");

	mtx_lock(&ac->ac_sc->amr_list_lock);
	xpt_done((union ccb *)csio);
	amr_releasecmd(ac);
	mtx_unlock(&ac->ac_sc->amr_list_lock);
}
Esempio n. 6
0
static cam_status
ptctor(struct cam_periph *periph, void *arg)
{
	struct pt_softc *softc;
	struct ccb_setasync csa;
	struct ccb_getdev *cgd;

	cgd = (struct ccb_getdev *)arg;
	if (periph == NULL) {
		printf("ptregister: periph was NULL!!\n");
		return(CAM_REQ_CMP_ERR);
	}

	if (cgd == NULL) {
		printf("ptregister: no getdev CCB, can't register device\n");
		return(CAM_REQ_CMP_ERR);
	}

	softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);

	if (softc == NULL) {
		printf("daregister: Unable to probe new device. "
		       "Unable to allocate softc\n");				
		return(CAM_REQ_CMP_ERR);
	}

	bzero(softc, sizeof(*softc));
	LIST_INIT(&softc->pending_ccbs);
	softc->state = PT_STATE_NORMAL;
	bioq_init(&softc->bio_queue);

	softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;

	periph->softc = softc;
	
	devstat_add_entry(&softc->device_stats, "pt",
			  periph->unit_number, 0,
			  DEVSTAT_NO_BLOCKSIZE,
			  SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
			  DEVSTAT_PRIORITY_OTHER);

	softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT,
			      GID_OPERATOR, 0600, "%s%d", periph->periph_name,
			      periph->unit_number);
	softc->dev->si_drv1 = periph;

	/*
	 * Add async callbacks for bus reset and
	 * bus device reset calls.  I don't bother
	 * checking if this fails as, in most cases,
	 * the system will function just fine without
	 * them and the only alternative would be to
	 * not attach the device on failure.
	 */
	xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
	csa.ccb_h.func_code = XPT_SASYNC_CB;
	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
	csa.callback = ptasync;
	csa.callback_arg = periph;
	xpt_action((union ccb *)&csa);

	/* Tell the user we've attached to the device */
	xpt_announce_periph(periph, NULL);

	return(CAM_REQ_CMP);
}