Ejemplo n.º 1
0
static void
ptstart(struct cam_periph *periph, union ccb *start_ccb)
{
	struct pt_softc *softc;
	struct buf *bp;
	struct bio *bio;

	softc = (struct pt_softc *)periph->softc;

	/*
	 * See if there is a buf with work for us to do..
	 */
	bio = bioq_first(&softc->bio_queue);
	if (periph->immediate_priority <= periph->pinfo.priority) {
		CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
				("queuing for immediate ccb\n"));
		start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
				  periph_links.sle);
		periph->immediate_priority = CAM_PRIORITY_NONE;
		wakeup(&periph->ccb_list);
	} else if (bio == NULL) {
		xpt_release_ccb(start_ccb);
	} else {
		bioq_remove(&softc->bio_queue, bio);
		bp = bio->bio_buf;

		devstat_start_transaction(&softc->device_stats);

		scsi_send_receive(&start_ccb->csio,
				  /*retries*/4,
				  ptdone,
				  MSG_SIMPLE_Q_TAG,
				  (bp->b_cmd == BUF_CMD_READ),
				  /*byte2*/0,
				  bp->b_bcount,
				  bp->b_data,
				  /*sense_len*/SSD_FULL_SIZE,
				  /*timeout*/softc->io_timeout);

		start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;

		/*
		 * Block out any asyncronous callbacks
		 * while we touch the pending ccb list.
		 */
		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
				 periph_links.le);

		start_ccb->ccb_h.ccb_bio = bio;
		bio = bioq_first(&softc->bio_queue);

		xpt_action(start_ccb);
		
		if (bio != NULL) {
			/* Have more work to do, so ensure we stay scheduled */
			xpt_schedule(periph, /* XXX priority */1);
		}
	}
}
Ejemplo n.º 2
0
static cam_status
pmpregister(struct cam_periph *periph, void *arg)
{
	struct pmp_softc *softc;
	struct ccb_getdev *cgd;

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

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

	softc = (struct pmp_softc *)malloc(sizeof(*softc), M_DEVBUF,
	    M_NOWAIT|M_ZERO);

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

	softc->pm_pid = ((uint32_t *)&cgd->ident_data)[0];
	softc->pm_prv = ((uint32_t *)&cgd->ident_data)[1];
	TASK_INIT(&softc->sysctl_task, 0, pmpsysctlinit, periph);

	xpt_announce_periph(periph, NULL);

	/*
	 * 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 |
		AC_SCSI_AEN, pmpasync, periph, periph->path);

	/*
	 * Take an exclusive refcount on the periph while pmpstart is called
	 * to finish the probe.  The reference will be dropped in pmpdone at
	 * the end of probe.
	 */
	(void)cam_periph_acquire(periph);
	xpt_hold_boot();
	softc->state = PMP_STATE_PORTS;
	softc->events = PMP_EV_RESCAN;
	xpt_schedule(periph, CAM_PRIORITY_DEV);

	return(CAM_REQ_CMP);
}
Ejemplo n.º 3
0
static void
adaschedule(struct cam_periph *periph)
{
	struct ada_softc *softc = (struct ada_softc *)periph->softc;

	if (bioq_first(&softc->bio_queue) ||
	    (!softc->trim_running && bioq_first(&softc->trim_queue))) {
		/* Have more work to do, so ensure we stay scheduled */
		xpt_schedule(periph, CAM_PRIORITY_NORMAL);
	}
}
Ejemplo n.º 4
0
/*
 * Actually translate the requested transfer into one the physical driver
 * can understand.  The transfer is described by a buf and will include
 * only one physical transfer.
 */
static void
ptstrategy(struct buf *bp)
{
	struct cam_periph *periph;
	struct pt_softc *softc;
	u_int  unit;
	int    s;
	
	unit = minor(bp->b_dev);
	periph = cam_extend_get(ptperiphs, unit);
	if (periph == NULL) {
		bp->b_error = ENXIO;
		goto bad;		
	}
	softc = (struct pt_softc *)periph->softc;

	/*
	 * Mask interrupts so that the pack cannot be invalidated until
	 * after we are in the queue.  Otherwise, we might not properly
	 * clean up one of the buffers.
	 */
	s = splbio();
	
	/*
	 * If the device has been made invalid, error out
	 */
	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
		splx(s);
		bp->b_error = ENXIO;
		goto bad;
	}
	
	/*
	 * Place it in the queue of disk activities for this disk
	 */
	bufq_insert_tail(&softc->buf_queue, bp);

	splx(s);
	
	/*
	 * Schedule ourselves for performing the work.
	 */
	xpt_schedule(periph, /* XXX priority */1);

	return;
bad:
	bp->b_flags |= B_ERROR;

	/*
	 * Correctly set the buf to indicate a completed xfer
	 */
	bp->b_resid = bp->b_bcount;
	biodone(bp);
}
Ejemplo n.º 5
0
static void
ptstart(struct cam_periph *periph, union ccb *start_ccb)
{
    struct pt_softc *softc;
    struct bio *bp;

    softc = (struct pt_softc *)periph->softc;

    CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptstart\n"));

    /*
     * See if there is a buf with work for us to do..
     */
    bp = bioq_first(&softc->bio_queue);
    if (bp == NULL) {
        xpt_release_ccb(start_ccb);
    } else {
        bioq_remove(&softc->bio_queue, bp);

        devstat_start_transaction_bio(softc->device_stats, bp);

        scsi_send_receive(&start_ccb->csio,
                          /*retries*/4,
                          ptdone,
                          MSG_SIMPLE_Q_TAG,
                          bp->bio_cmd == BIO_READ,
                          /*byte2*/0,
                          bp->bio_bcount,
                          bp->bio_data,
                          /*sense_len*/SSD_FULL_SIZE,
                          /*timeout*/softc->io_timeout);

        start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;

        /*
         * Block out any asynchronous callbacks
         * while we touch the pending ccb list.
         */
        LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
                         periph_links.le);

        start_ccb->ccb_h.ccb_bp = bp;
        bp = bioq_first(&softc->bio_queue);

        xpt_action(start_ccb);

        if (bp != NULL) {
            /* Have more work to do, so ensure we stay scheduled */
            xpt_schedule(periph, CAM_PRIORITY_NORMAL);
        }
    }
}
Ejemplo n.º 6
0
/*
 * Actually translate the requested transfer into one the physical driver
 * can understand.  The transfer is described by a buf and will include
 * only one physical transfer.
 */
static int
ptstrategy(struct dev_strategy_args *ap)
{
	cdev_t dev = ap->a_head.a_dev;
	struct bio *bio = ap->a_bio;
	struct buf *bp = bio->bio_buf;
	struct cam_periph *periph;
	struct pt_softc *softc;
	u_int  unit;
	
	unit = minor(dev);
	periph = cam_extend_get(ptperiphs, unit);
	if (periph == NULL) {
		bp->b_error = ENXIO;
		goto bad;		
	}
	cam_periph_lock(periph);
	softc = (struct pt_softc *)periph->softc;

	/*
	 * If the device has been made invalid, error out
	 */
	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
		cam_periph_unlock(periph);
		bp->b_error = ENXIO;
		goto bad;
	}
	
	/*
	 * Place it in the queue of disk activities for this disk
	 */
	bioq_insert_tail(&softc->bio_queue, bio);
	
	/*
	 * Schedule ourselves for performing the work.
	 */
	xpt_schedule(periph, /* XXX priority */1);
	cam_periph_unlock(periph);

	return(0);
bad:
	bp->b_flags |= B_ERROR;

	/*
	 * Correctly set the buf to indicate a completed xfer
	 */
	bp->b_resid = bp->b_bcount;
	biodone(bio);
	return(0);
}
Ejemplo n.º 7
0
/*
 * Actually translate the requested transfer into one the physical driver
 * can understand.  The transfer is described by a buf and will include
 * only one physical transfer.
 */
static void
ptstrategy(struct bio *bp)
{
	struct cam_periph *periph;
	struct pt_softc *softc;
	int    s;
	
	periph = (struct cam_periph *)bp->bio_dev->si_drv1;
	bp->bio_resid = bp->bio_bcount;
	if (periph == NULL) {
		biofinish(bp, NULL, ENXIO);
		return;
	}
	softc = (struct pt_softc *)periph->softc;

	/*
	 * Mask interrupts so that the pack cannot be invalidated until
	 * after we are in the queue.  Otherwise, we might not properly
	 * clean up one of the buffers.
	 */
	s = splbio();
	
	/*
	 * If the device has been made invalid, error out
	 */
	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
		splx(s);
		biofinish(bp, NULL, ENXIO);
		return;
	}
	
	/*
	 * Place it in the queue of disk activities for this disk
	 */
	bioq_insert_tail(&softc->bio_queue, bp);

	splx(s);
	
	/*
	 * Schedule ourselves for performing the work.
	 */
	xpt_schedule(periph, /* XXX priority */1);

	return;
}
Ejemplo n.º 8
0
static void
adaschedule(struct cam_periph *periph)
{
	struct ada_softc *softc = (struct ada_softc *)periph->softc;
	uint32_t prio;

	/* Check if cam_periph_getccb() was called. */
	prio = periph->immediate_priority;

	/* Check if we have more work to do. */
	if (bioq_first(&softc->bio_queue) ||
	    (!softc->trim_running && bioq_first(&softc->trim_queue))) {
		prio = CAM_PRIORITY_NORMAL;
	}

	/* Schedule CCB if any of above is true. */
	if (prio != CAM_PRIORITY_NONE)
		xpt_schedule(periph, prio);
}
Ejemplo n.º 9
0
/*
 * Actually translate the requested transfer into one the physical driver
 * can understand.  The transfer is described by a buf and will include
 * only one physical transfer.
 */
static void
ptstrategy(struct bio *bp)
{
	struct cam_periph *periph;
	struct pt_softc *softc;
	
	periph = (struct cam_periph *)bp->bio_dev->si_drv1;
	bp->bio_resid = bp->bio_bcount;
	if (periph == NULL) {
		biofinish(bp, NULL, ENXIO);
		return;
	}
	cam_periph_lock(periph);
	softc = (struct pt_softc *)periph->softc;

	/*
	 * If the device has been made invalid, error out
	 */
	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
		cam_periph_unlock(periph);
		biofinish(bp, NULL, ENXIO);
		return;
	}
	
	/*
	 * Place it in the queue of disk activities for this disk
	 */
	bioq_insert_tail(&softc->bio_queue, bp);

	/*
	 * Schedule ourselves for performing the work.
	 */
	xpt_schedule(periph, /* XXX priority */1);
	cam_periph_unlock(periph);

	return;
}
Ejemplo n.º 10
0
static void
pmpdone(struct cam_periph *periph, union ccb *done_ccb)
{
	struct ccb_trans_settings cts;
	struct pmp_softc *softc;
	struct ccb_ataio *ataio;
	struct cam_path *dpath;
	u_int32_t  priority, res;
	int i;

	softc = (struct pmp_softc *)periph->softc;
	ataio = &done_ccb->ataio;

	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("pmpdone\n"));

	priority = done_ccb->ccb_h.pinfo.priority;

	if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
		if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART) {
			return;
		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
			cam_release_devq(done_ccb->ccb_h.path,
			    /*relsim_flags*/0,
			    /*reduction*/0,
			    /*timeout*/0,
			    /*getcount_only*/0);
		}
		goto done;
	}

	if (softc->restart) {
		softc->restart = 0;
		xpt_release_ccb(done_ccb);
		softc->state = min(softc->state, PMP_STATE_PRECONFIG);
		xpt_schedule(periph, priority);
		return;
	}

	switch (softc->state) {
	case PMP_STATE_PORTS:
		softc->pm_ports = (ataio->res.lba_high << 24) +
		    (ataio->res.lba_mid << 16) +
		    (ataio->res.lba_low << 8) +
		    ataio->res.sector_count;
		if (pmp_hide_special) {
			/*
			 * This PMP declares 6 ports, while only 5 of them
			 * are real. Port 5 is a SEMB port, probing which
			 * causes timeouts if external SEP is not connected
			 * to PMP over I2C.
			 */
			if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6)
				softc->pm_ports = 5;

			/*
			 * This PMP declares 7 ports, while only 5 of them
			 * are real. Port 5 is a fake "Config  Disk" with
			 * 640 sectors size. Port 6 is a SEMB port.
			 */
			if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7)
				softc->pm_ports = 5;

			/*
			 * These PMPs have extra configuration port.
			 */
			if (softc->pm_pid == 0x57231095 ||
			    softc->pm_pid == 0x57331095 ||
			    softc->pm_pid == 0x57341095 ||
			    softc->pm_pid == 0x57441095)
				softc->pm_ports--;
		}
		printf("%s%d: %d fan-out ports\n",
		    periph->periph_name, periph->unit_number,
		    softc->pm_ports);
		softc->state = PMP_STATE_PRECONFIG;
		xpt_release_ccb(done_ccb);
		xpt_schedule(periph, priority);
		return;
	case PMP_STATE_PRECONFIG:
		softc->pm_step = 0;
		softc->state = PMP_STATE_RESET;
		softc->reset |= ~softc->found;
		xpt_release_ccb(done_ccb);
		xpt_schedule(periph, priority);
		return;
	case PMP_STATE_RESET:
		softc->pm_step++;
		if (softc->pm_step >= softc->pm_ports) {
			softc->pm_step = 0;
			cam_freeze_devq(periph->path);
			cam_release_devq(periph->path,
			    RELSIM_RELEASE_AFTER_TIMEOUT,
			    /*reduction*/0,
			    /*timeout*/5,
			    /*getcount_only*/0);
			softc->state = PMP_STATE_CONNECT;
		}
		xpt_release_ccb(done_ccb);
		xpt_schedule(periph, priority);
		return;
	case PMP_STATE_CONNECT:
		softc->pm_step++;
		if (softc->pm_step >= softc->pm_ports) {
			softc->pm_step = 0;
			softc->pm_try = 0;
			cam_freeze_devq(periph->path);
			cam_release_devq(periph->path,
			    RELSIM_RELEASE_AFTER_TIMEOUT,
			    /*reduction*/0,
			    /*timeout*/10,
			    /*getcount_only*/0);
			softc->state = PMP_STATE_CHECK;
		}
		xpt_release_ccb(done_ccb);
		xpt_schedule(periph, priority);
		return;
	case PMP_STATE_CHECK:
		res = (ataio->res.lba_high << 24) +
		    (ataio->res.lba_mid << 16) +
		    (ataio->res.lba_low << 8) +
		    ataio->res.sector_count;
		if (((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) ||
		    (res & 0x600) != 0) {
			if (bootverbose) {
				printf("%s%d: port %d status: %08x\n",
				    periph->periph_name, periph->unit_number,
				    softc->pm_step, res);
			}
			/* Report device speed if it is online. */
			if ((res & 0xf0f) == 0x103 &&
			    xpt_create_path(&dpath, periph,
			    xpt_path_path_id(periph->path),
			    softc->pm_step, 0) == CAM_REQ_CMP) {
				bzero(&cts, sizeof(cts));
				xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE);
				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
				cts.type = CTS_TYPE_CURRENT_SETTINGS;
				cts.xport_specific.sata.revision = (res & 0x0f0) >> 4;
				cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION;
				cts.xport_specific.sata.caps = softc->caps &
				    (CTS_SATA_CAPS_H_PMREQ |
				     CTS_SATA_CAPS_H_DMAAA |
				     CTS_SATA_CAPS_H_AN);
				cts.xport_specific.sata.valid |= CTS_SATA_VALID_CAPS;
				xpt_action((union ccb *)&cts);
				xpt_free_path(dpath);
			}
			softc->found |= (1 << softc->pm_step);
			softc->pm_step++;
		} else {
			if (softc->pm_try < 10) {
Ejemplo n.º 11
0
static void
pmpasync(void *callback_arg, u_int32_t code,
	struct cam_path *path, void *arg)
{
	struct cam_periph *periph;
	struct pmp_softc *softc;

	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_SATAPM)
			break;

		/*
		 * Allocate a peripheral instance for
		 * this device and start the probe
		 * process.
		 */
		status = cam_periph_alloc(pmpregister, pmponinvalidate,
					  pmpcleanup, pmpstart,
					  "pmp", CAM_PERIPH_BIO,
					  cgd->ccb_h.path, pmpasync,
					  AC_FOUND_DEVICE, cgd);

		if (status != CAM_REQ_CMP
		 && status != CAM_REQ_INPROG)
			printf("pmpasync: Unable to attach to new device "
				"due to status 0x%x\n", status);
		break;
	}
	case AC_SCSI_AEN:
	case AC_SENT_BDR:
	case AC_BUS_RESET:
		softc = (struct pmp_softc *)periph->softc;
		cam_periph_async(periph, code, path, arg);
		if (code == AC_SCSI_AEN)
			softc->events |= PMP_EV_RESCAN;
		else
			softc->events |= PMP_EV_RESET;
		if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL)
			break;
		xpt_hold_boot();
		pmpfreeze(periph, softc->found);
		if (code == AC_SENT_BDR || code == AC_BUS_RESET)
			softc->found = 0; /* We have to reset everything. */
		if (softc->state == PMP_STATE_NORMAL) {
			softc->state = PMP_STATE_PRECONFIG;
			cam_periph_acquire(periph);
			xpt_schedule(periph, CAM_PRIORITY_DEV);
		} else
			softc->restart = 1;
		break;
	default:
		cam_periph_async(periph, code, path, arg);
		break;
	}
}