diff options
Diffstat (limited to 'sys/dev/firewire/sbp.c')
-rw-r--r-- | sys/dev/firewire/sbp.c | 247 |
1 files changed, 167 insertions, 80 deletions
diff --git a/sys/dev/firewire/sbp.c b/sys/dev/firewire/sbp.c index 13b9aa1..59f3d87 100644 --- a/sys/dev/firewire/sbp.c +++ b/sys/dev/firewire/sbp.c @@ -39,34 +39,48 @@ #include <sys/systm.h> #include <sys/module.h> #include <sys/bus.h> +#include <sys/kernel.h> #include <sys/sysctl.h> #include <machine/bus.h> #include <sys/malloc.h> -#if __FreeBSD_version >= 501102 +#if defined(__FreeBSD__) && __FreeBSD_version >= 501102 #include <sys/lock.h> #include <sys/mutex.h> #endif -#if __FreeBSD_version < 500106 +#if defined(__DragonFly__) || __FreeBSD_version < 500106 #include <sys/devicestat.h> /* for struct devstat */ #endif +#ifdef __DragonFly__ +#include <bus/cam/cam.h> +#include <bus/cam/cam_ccb.h> +#include <bus/cam/cam_sim.h> +#include <bus/cam/cam_xpt_sim.h> +#include <bus/cam/cam_debug.h> +#include <bus/cam/cam_periph.h> +#include <bus/cam/scsi/scsi_all.h> + +#include <bus/firewire/firewire.h> +#include <bus/firewire/firewirereg.h> +#include <bus/firewire/fwdma.h> +#include <bus/firewire/iec13213.h> +#include "sbp.h" +#else #include <cam/cam.h> #include <cam/cam_ccb.h> #include <cam/cam_sim.h> #include <cam/cam_xpt_sim.h> #include <cam/cam_debug.h> #include <cam/cam_periph.h> - #include <cam/scsi/scsi_all.h> -#include <sys/kernel.h> - #include <dev/firewire/firewire.h> #include <dev/firewire/firewirereg.h> #include <dev/firewire/fwdma.h> #include <dev/firewire/iec13213.h> #include <dev/firewire/sbp.h> +#endif #define ccb_sdev_ptr spriv_ptr0 #define ccb_sbp_ptr spriv_ptr1 @@ -113,6 +127,8 @@ static int sbp_cold = 1; static int ex_login = 1; static int login_delay = 1000; /* msec */ static int scan_delay = 500; /* msec */ +static int use_doorbell = 0; +static int sbp_tags = 0; SYSCTL_DECL(_hw_firewire); SYSCTL_NODE(_hw_firewire, OID_AUTO, sbp, CTLFLAG_RD, 0, "SBP-II Subsystem"); @@ -128,12 +144,18 @@ SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, login_delay, CTLFLAG_RW, &login_delay, 0, "SBP login delay in msec"); SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, scan_delay, CTLFLAG_RW, &scan_delay, 0, "SBP scan delay in msec"); +SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, use_doorbell, CTLFLAG_RW, + &use_doorbell, 0, "SBP use doorbell request"); +SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, tags, CTLFLAG_RW, &sbp_tags, 0, + "SBP tagged queuing support"); TUNABLE_INT("hw.firewire.sbp.auto_login", &auto_login); TUNABLE_INT("hw.firewire.sbp.max_speed", &max_speed); TUNABLE_INT("hw.firewire.sbp.exclusive_login", &ex_login); TUNABLE_INT("hw.firewire.sbp.login_delay", &login_delay); TUNABLE_INT("hw.firewire.sbp.scan_delay", &scan_delay); +TUNABLE_INT("hw.firewire.sbp.use_doorbell", &use_doorbell); +TUNABLE_INT("hw.firewire.sbp.tags", &sbp_tags); #define NEED_RESPONSE 0 @@ -179,6 +201,9 @@ struct sbp_dev{ #define VALID_LUN (1 << 1) #define ORB_POINTER_ACTIVE (1 << 2) #define ORB_POINTER_NEED (1 << 3) +#define ORB_DOORBELL_ACTIVE (1 << 4) +#define ORB_DOORBELL_NEED (1 << 5) +#define ORB_SHORTAGE (1 << 6) u_int16_t flags; struct cam_path *path; struct sbp_target *target; @@ -188,6 +213,7 @@ struct sbp_dev{ struct sbp_ocb *ocb; STAILQ_HEAD(, sbp_ocb) ocbs; STAILQ_HEAD(, sbp_ocb) free_ocbs; + struct sbp_ocb *last_ocb; char vendor[32]; char product[32]; char revision[10]; @@ -227,6 +253,7 @@ static void sbp_mgm_callback (struct fw_xfer *); static void sbp_cmd_callback (struct fw_xfer *); #endif static void sbp_orb_pointer (struct sbp_dev *, struct sbp_ocb *); +static void sbp_doorbell(struct sbp_dev *); static void sbp_execute_ocb (void *, bus_dma_segment_t *, int, int); static void sbp_free_ocb (struct sbp_dev *, struct sbp_ocb *); static void sbp_abort_ocb (struct sbp_ocb *, int); @@ -468,7 +495,7 @@ END_DEBUG M_SBP, M_NOWAIT | M_ZERO); if (newluns == NULL) { - printf("%s: realloc failed\n", __FUNCTION__); + printf("%s: realloc failed\n", __func__); newluns = target->luns; maxlun = target->num_lun; } @@ -504,7 +531,7 @@ END_DEBUG sdev = malloc(sizeof(struct sbp_dev), M_SBP, M_NOWAIT | M_ZERO); if (sdev == NULL) { - printf("%s: malloc failed\n", __FUNCTION__); + printf("%s: malloc failed\n", __func__); goto next; } target->luns[lun] = sdev; @@ -526,7 +553,7 @@ END_DEBUG SBP_DMA_SIZE, &sdev->dma, BUS_DMA_NOWAIT); if (sdev->dma.v_addr == NULL) { printf("%s: dma space allocation failed\n", - __FUNCTION__); + __func__); free(sdev, M_SBP); target->luns[lun] = NULL; goto next; @@ -668,7 +695,7 @@ sbp_login(struct sbp_dev *sdev) if (t.tv_sec >= 0 && t.tv_usec > 0) ticks = (t.tv_sec * 1000 + t.tv_usec / 1000) * hz / 1000; SBP_DEBUG(0) - printf("%s: sec = %ld usec = %ld ticks = %d\n", __FUNCTION__, + printf("%s: sec = %ld usec = %ld ticks = %d\n", __func__, t.tv_sec, t.tv_usec, ticks); END_DEBUG callout_reset(&sdev->login_callout, ticks, @@ -1068,11 +1095,11 @@ sbp_agent_reset_callback(struct fw_xfer *xfer) sdev = (struct sbp_dev *)xfer->sc; SBP_DEBUG(1) sbp_show_sdev_info(sdev, 2); - printf("%s\n", __FUNCTION__); + printf("%s\n", __func__); END_DEBUG if (xfer->resp != 0) { sbp_show_sdev_info(sdev, 2); - printf("%s: resp=%d\n", __FUNCTION__, xfer->resp); + printf("%s: resp=%d\n", __func__, xfer->resp); } sbp_xfer_free(xfer); @@ -1146,11 +1173,11 @@ sbp_orb_pointer_callback(struct fw_xfer *xfer) SBP_DEBUG(1) sbp_show_sdev_info(sdev, 2); - printf("%s\n", __FUNCTION__); + printf("%s\n", __func__); END_DEBUG if (xfer->resp != 0) { /* XXX */ - printf("%s: xfer->resp = %d\n", __FUNCTION__, xfer->resp); + printf("%s: xfer->resp = %d\n", __func__, xfer->resp); } sbp_xfer_free(xfer); sdev->flags &= ~ORB_POINTER_ACTIVE; @@ -1173,12 +1200,12 @@ sbp_orb_pointer(struct sbp_dev *sdev, struct sbp_ocb *ocb) struct fw_pkt *fp; SBP_DEBUG(1) sbp_show_sdev_info(sdev, 2); - printf("%s: 0x%08x\n", __FUNCTION__, (u_int32_t)ocb->bus_addr); + printf("%s: 0x%08x\n", __func__, (u_int32_t)ocb->bus_addr); END_DEBUG if ((sdev->flags & ORB_POINTER_ACTIVE) != 0) { SBP_DEBUG(0) - printf("%s: orb pointer active\n", __FUNCTION__); + printf("%s: orb pointer active\n", __func__); END_DEBUG sdev->flags |= ORB_POINTER_NEED; return; @@ -1204,21 +1231,26 @@ END_DEBUG } } -#if 0 static void -sbp_cmd_callback(struct fw_xfer *xfer) +sbp_doorbell_callback(struct fw_xfer *xfer) { -SBP_DEBUG(1) struct sbp_dev *sdev; sdev = (struct sbp_dev *)xfer->sc; + +SBP_DEBUG(1) sbp_show_sdev_info(sdev, 2); - printf("sbp_cmd_callback\n"); + printf("sbp_doorbell_callback\n"); END_DEBUG if (xfer->resp != 0) { /* XXX */ - printf("%s: xfer->resp = %d\n", __FUNCTION__, xfer->resp); + printf("%s: xfer->resp = %d\n", __func__, xfer->resp); } sbp_xfer_free(xfer); + sdev->flags &= ~ORB_DOORBELL_ACTIVE; + if ((sdev->flags & ORB_DOORBELL_NEED) != 0) { + sdev->flags &= ~ORB_DOORBELL_NEED; + sbp_doorbell(sdev); + } return; } @@ -1232,15 +1264,19 @@ SBP_DEBUG(1) printf("sbp_doorbell\n"); END_DEBUG + if ((sdev->flags & ORB_DOORBELL_ACTIVE) != 0) { + sdev->flags |= ORB_DOORBELL_NEED; + return; + } + sdev->flags |= ORB_DOORBELL_ACTIVE; xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0x10); if (xfer == NULL) return; - xfer->act.hand = sbp_cmd_callback; - fp = (struct fw_pkt *)xfer->send.buf; + xfer->act.hand = sbp_doorbell_callback; + fp = &xfer->send.hdr; fp->mode.wreqq.data = htonl(0xf); fw_asyreq(xfer->fc, -1, xfer); } -#endif static struct fw_xfer * sbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset) @@ -1539,10 +1575,6 @@ END_DEBUG #endif /* fall through */ case T_RBC: - /* enable tagged queuing */ -#if 1 - inq->flags |= SID_CmdQue; -#endif /* * Override vendor/product/revision information. * Some devices sometimes return strange strings. @@ -1554,6 +1586,15 @@ END_DEBUG #endif break; } + /* + * Force to enable/disable tagged queuing. + * XXX CAM also checks SCP_QUEUE_DQUE flag in the control mode page. + */ + if (sbp_tags > 0) + inq->flags |= SID_CmdQue; + else if (sbp_tags < 0) + inq->flags &= ~SID_CmdQue; + } static void @@ -1629,10 +1670,10 @@ END_DEBUG ocb = sbp_dequeue_ocb(sdev, sbp_status); if (ocb == NULL) { sbp_show_sdev_info(sdev, 2); -#if __FreeBSD_version >= 500000 - printf("No ocb(%x) on the queue\n", -#else +#if defined(__DragonFly__) || __FreeBSD_version < 500000 printf("No ocb(%lx) on the queue\n", +#else + printf("No ocb(%x) on the queue\n", #endif ntohl(sbp_status->orb_lo)); } @@ -1657,10 +1698,10 @@ END_DEBUG SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("ORB status src:%x resp:%x dead:%x" -#if __FreeBSD_version >= 500000 - " len:%x stat:%x orb:%x%08x\n", -#else +#if defined(__DragonFly__) || __FreeBSD_version < 500000 " len:%x stat:%x orb:%x%08lx\n", +#else + " len:%x stat:%x orb:%x%08x\n", #endif sbp_status->src, sbp_status->resp, sbp_status->dead, sbp_status->len, sbp_status->status, @@ -1811,7 +1852,8 @@ printf("len %d\n", sbp_status->len); } } - sbp_free_ocb(sdev, ocb); + if (!use_doorbell) + sbp_free_ocb(sdev, ocb); done: if (reset_agent) sbp_agent_reset(sdev); @@ -1893,7 +1935,7 @@ END_DEBUG /*maxsize*/0x100000, /*nsegments*/SBP_IND_MAX, /*maxsegsz*/SBP_SEG_MAX, /*flags*/BUS_DMA_ALLOCNOW, -#if __FreeBSD_version >= 501102 +#if defined(__FreeBSD__) && __FreeBSD_version >= 501102 /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant, #endif @@ -2340,6 +2382,10 @@ END_DEBUG #endif if ((ocb = sbp_get_ocb(sdev)) == NULL) { ccb->ccb_h.status = CAM_REQUEUE_REQ; + if (sdev->freeze == 0) { + xpt_freeze_devq(sdev->path, 1); + sdev->freeze ++; + } xpt_done(ccb); return; } @@ -2394,7 +2440,7 @@ printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[4]), ntohl(ocb->orb[5]), ntoh case XPT_CALC_GEOMETRY: { struct ccb_calc_geometry *ccg; -#if __FreeBSD_version < 501100 +#if defined(__DragonFly__) || __FreeBSD_version < 501100 u_int32_t size_mb; u_int32_t secs_per_cylinder; int extended = 1; @@ -2409,21 +2455,21 @@ printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[4]), ntohl(ocb->orb[5]), ntoh } SBP_DEBUG(1) printf("%s:%d:%d:%d:XPT_CALC_GEOMETRY: " -#if __FreeBSD_version >= 500000 - "Volume size = %jd\n", -#else +#if defined(__DragonFly__) || __FreeBSD_version < 500000 "Volume size = %d\n", +#else + "Volume size = %jd\n", #endif device_get_nameunit(sbp->fd.dev), cam_sim_path(sbp->sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, -#if __FreeBSD_version >= 500000 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 (uintmax_t) #endif ccg->volume_size); END_DEBUG -#if __FreeBSD_version < 501100 +#if defined(__DragonFly__) || __FreeBSD_version < 501100 size_mb = ccg->volume_size / ((1024L * 1024L) / ccg->block_size); @@ -2539,11 +2585,11 @@ sbp_execute_ocb(void *arg, bus_dma_segment_t *segments, int seg, int error) SBP_DEBUG(2) printf("sbp_execute_ocb: seg %d", seg); for (i = 0; i < seg; i++) -#if __FreeBSD_version >= 500000 +#if defined(__DragonFly__) || __FreeBSD_version < 500000 + printf(", %x:%d", segments[i].ds_addr, segments[i].ds_len); +#else printf(", %jx:%jd", (uintmax_t)segments[i].ds_addr, (uintmax_t)segments[i].ds_len); -#else - printf(", %x:%d", segments[i].ds_addr, segments[i].ds_len); #endif printf("\n"); END_DEBUG @@ -2563,10 +2609,10 @@ SBP_DEBUG(0) /* XXX LSI Logic "< 16 byte" bug might be hit */ if (s->ds_len < 16) printf("sbp_execute_ocb: warning, " -#if __FreeBSD_version >= 500000 - "segment length(%zd) is less than 16." -#else +#if defined(__DragonFly__) || __FreeBSD_version < 500000 "segment length(%d) is less than 16." +#else + "segment length(%zd) is less than 16." #endif "(seg=%d/%d)\n", s->ds_len, i+1, seg); END_DEBUG @@ -2584,9 +2630,18 @@ END_DEBUG BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); prev = sbp_enqueue_ocb(ocb->sdev, ocb); fwdma_sync(&ocb->sdev->dma, BUS_DMASYNC_PREWRITE); - if (prev == NULL || (ocb->sdev->flags & ORB_LINK_DEAD) != 0) { - ocb->sdev->flags &= ~ORB_LINK_DEAD; - sbp_orb_pointer(ocb->sdev, ocb); + if (use_doorbell) { + if (prev == NULL) { + if (ocb->sdev->last_ocb != NULL) + sbp_doorbell(ocb->sdev); + else + sbp_orb_pointer(ocb->sdev, ocb); + } + } else { + if (prev == NULL || (ocb->sdev->flags & ORB_LINK_DEAD) != 0) { + ocb->sdev->flags &= ~ORB_LINK_DEAD; + sbp_orb_pointer(ocb->sdev, ocb); + } } } @@ -2614,12 +2669,12 @@ sbp_dequeue_ocb(struct sbp_dev *sdev, struct sbp_status *sbp_status) SBP_DEBUG(1) sbp_show_sdev_info(sdev, 2); -#if __FreeBSD_version >= 500000 - printf("%s: 0x%08x src %d\n", -#else +#if defined(__DragonFly__) || __FreeBSD_version < 500000 printf("%s: 0x%08lx src %d\n", +#else + printf("%s: 0x%08x src %d\n", #endif - __FUNCTION__, ntohl(sbp_status->orb_lo), sbp_status->src); + __func__, ntohl(sbp_status->orb_lo), sbp_status->src); END_DEBUG for (ocb = STAILQ_FIRST(&sdev->ocbs); ocb != NULL; ocb = next) { next = STAILQ_NEXT(ocb, ocb); @@ -2639,17 +2694,30 @@ END_DEBUG bus_dmamap_unload(sdev->target->sbp->dmat, ocb->dmamap); } - if (sbp_status->src == SRC_NO_NEXT) { - if (next != NULL) - sbp_orb_pointer(sdev, next); - else if (order > 0) { - /* - * Unordered execution - * We need to send pointer for - * next ORB - */ - sdev->flags |= ORB_LINK_DEAD; + if (!use_doorbell) { + if (sbp_status->src == SRC_NO_NEXT) { + if (next != NULL) + sbp_orb_pointer(sdev, next); + else if (order > 0) { + /* + * Unordered execution + * We need to send pointer for + * next ORB + */ + sdev->flags |= ORB_LINK_DEAD; + } } + } else { + /* + * XXX this is not correct for unordered + * execution. + */ + if (sdev->last_ocb != NULL) + sbp_free_ocb(sdev, sdev->last_ocb); + sdev->last_ocb = ocb; + if (next != NULL && + sbp_status->src == SRC_NO_NEXT) + sbp_doorbell(sdev); } break; } else @@ -2669,35 +2737,38 @@ static struct sbp_ocb * sbp_enqueue_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb) { int s = splfw(); - struct sbp_ocb *prev; + struct sbp_ocb *prev, *prev2; SBP_DEBUG(1) sbp_show_sdev_info(sdev, 2); -#if __FreeBSD_version >= 500000 - printf("%s: 0x%08jx\n", __FUNCTION__, (uintmax_t)ocb->bus_addr); +#if defined(__DragonFly__) || __FreeBSD_version < 500000 + printf("%s: 0x%08x\n", __func__, ocb->bus_addr); #else - printf("%s: 0x%08x\n", __FUNCTION__, ocb->bus_addr); + printf("%s: 0x%08jx\n", __func__, (uintmax_t)ocb->bus_addr); #endif END_DEBUG - prev = STAILQ_LAST(&sdev->ocbs, sbp_ocb, ocb); + prev2 = prev = STAILQ_LAST(&sdev->ocbs, sbp_ocb, ocb); STAILQ_INSERT_TAIL(&sdev->ocbs, ocb, ocb); if (ocb->ccb != NULL) ocb->ccb->ccb_h.timeout_ch = timeout(sbp_timeout, (caddr_t)ocb, (ocb->ccb->ccb_h.timeout * hz) / 1000); - if (prev != NULL) { + if (use_doorbell && prev == NULL) + prev2 = sdev->last_ocb; + + if (prev2 != NULL) { SBP_DEBUG(2) -#if __FreeBSD_version >= 500000 - printf("linking chain 0x%jx -> 0x%jx\n", - (uintmax_t)prev->bus_addr, (uintmax_t)ocb->bus_addr); -#else +#if defined(__DragonFly__) || __FreeBSD_version < 500000 printf("linking chain 0x%x -> 0x%x\n", - prev->bus_addr, ocb->bus_addr); + prev2->bus_addr, ocb->bus_addr); +#else + printf("linking chain 0x%jx -> 0x%jx\n", + (uintmax_t)prev2->bus_addr, (uintmax_t)ocb->bus_addr); #endif END_DEBUG - prev->orb[1] = htonl(ocb->bus_addr); - prev->orb[0] = 0; + prev2->orb[1] = htonl(ocb->bus_addr); + prev2->orb[0] = 0; } splx(s); @@ -2711,6 +2782,7 @@ sbp_get_ocb(struct sbp_dev *sdev) int s = splfw(); ocb = STAILQ_FIRST(&sdev->free_ocbs); if (ocb == NULL) { + sdev->flags |= ORB_SHORTAGE; printf("ocb shortage!!!\n"); return NULL; } @@ -2726,6 +2798,14 @@ sbp_free_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb) ocb->flags = 0; ocb->ccb = NULL; STAILQ_INSERT_TAIL(&sdev->free_ocbs, ocb, ocb); + if ((sdev->flags & ORB_SHORTAGE) != 0) { + int count; + + sdev->flags &= ~ORB_SHORTAGE; + count = sdev->freeze; + sdev->freeze = 0; + xpt_release_devq(sdev->path, count, TRUE); + } } static void @@ -2736,10 +2816,10 @@ sbp_abort_ocb(struct sbp_ocb *ocb, int status) sdev = ocb->sdev; SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); -#if __FreeBSD_version >= 500000 - printf("sbp_abort_ocb 0x%jx\n", (uintmax_t)ocb->bus_addr); -#else +#if defined(__DragonFly__) || __FreeBSD_version < 500000 printf("sbp_abort_ocb 0x%x\n", ocb->bus_addr); +#else + printf("sbp_abort_ocb 0x%jx\n", (uintmax_t)ocb->bus_addr); #endif END_DEBUG SBP_DEBUG(1) @@ -2776,6 +2856,10 @@ sbp_abort_all_ocbs(struct sbp_dev *sdev, int status) next = STAILQ_NEXT(ocb, ocb); sbp_abort_ocb(ocb, status); } + if (sdev->last_ocb != NULL) { + sbp_free_ocb(sdev, sdev->last_ocb); + sdev->last_ocb = NULL; + } splx(s); } @@ -2798,6 +2882,9 @@ static driver_t sbp_driver = { sbp_methods, sizeof(struct sbp_softc), }; +#ifdef __DragonFly__ +DECLARE_DUMMY_MODULE(sbp); +#endif DRIVER_MODULE(sbp, firewire, sbp_driver, sbp_devclass, 0, 0); MODULE_VERSION(sbp, 1); MODULE_DEPEND(sbp, firewire, 1, 1, 1); |