diff options
author | simokawa <simokawa@FreeBSD.org> | 2003-02-27 12:51:24 +0000 |
---|---|---|
committer | simokawa <simokawa@FreeBSD.org> | 2003-02-27 12:51:24 +0000 |
commit | 15b70bcd2e4f67772c1a7611a7f17d291acbff3f (patch) | |
tree | 9dc6d0572414885de0d9b6a17ee7854130b3e2e9 | |
parent | 6eb790939b8d733c0cad2a9b724d11fb1c5c344e (diff) | |
download | FreeBSD-src-15b70bcd2e4f67772c1a7611a7f17d291acbff3f.zip FreeBSD-src-15b70bcd2e4f67772c1a7611a7f17d291acbff3f.tar.gz |
MFp4(simokawa_sbp branch)
Improve SBP device probeing:
- Wait 2 sec before issuing LOGIN ORB expecting the reconnection
hold timer expires.
- Serialize management ORB and scanning LUN by CAM on each target.
This should fix the problem for devices which have multiple LUNs.
Test device is donated by: Jaye Mathisen <mrcpu@internetcds.com>
- Freeze SIM queue for 2 sec after BUS RESET.
- Retry with LOGIN rather than RECONNECT after LOGIN is not completed for
BUS RESET.
- Use appropriate CAM status for BUS RESET and DEVICE RESET.
- Let CAM to scan targets after BUS REST.
- Implement CAM scan target function.
- Keep our own devq freeze count.
- Let CAM to know that SBP does tagged queuing.
These should be merged to RELENG_4 before 4.8-RELEASE.
-rw-r--r-- | sys/dev/firewire/firewire.c | 12 | ||||
-rw-r--r-- | sys/dev/firewire/firewirereg.h | 6 | ||||
-rw-r--r-- | sys/dev/firewire/fwdev.c | 8 | ||||
-rw-r--r-- | sys/dev/firewire/fwmem.c | 4 | ||||
-rw-r--r-- | sys/dev/firewire/sbp.c | 388 |
5 files changed, 310 insertions, 108 deletions
diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index b25ede6..afd65e5 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -423,11 +423,6 @@ firewire_attach( device_t dev ) #else sc->dev[i] = d; #endif -#if __FreeBSD_version >= 500000 -#define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */) -#else -#define CALLOUT_INIT(x) callout_init(x) -#endif CALLOUT_INIT(&sc->fc->timeout_callout); CALLOUT_INIT(&sc->fc->bmr_callout); CALLOUT_INIT(&sc->fc->retry_probe_callout); @@ -1787,13 +1782,14 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u ntohl(fp->mode.rreqq.dest_lo)); if(bind == NULL){ #if __FreeBSD_version >= 500000 - printf("Unknown service addr 0x%08x:0x%08x tcode=%x\n", + printf("Unknown service addr 0x%08x:0x%08x tcode=%x\n src=0x%x", #else - printf("Unknown service addr 0x%08x:0x%08lx tcode=%x\n", + printf("Unknown service addr 0x%08x:0x%08lx tcode=%x src=0x%x\n", #endif ntohs(fp->mode.rreqq.dest_hi), ntohl(fp->mode.rreqq.dest_lo), - fp->mode.common.tcode); + fp->mode.common.tcode, + fp->mode.hdr.src); if (fc->status == FWBUSRESET) { printf("fw_rcv: cannot respond(bus reset)!\n"); goto err; diff --git a/sys/dev/firewire/firewirereg.h b/sys/dev/firewire/firewirereg.h index 0998575..9cbcadf 100644 --- a/sys/dev/firewire/firewirereg.h +++ b/sys/dev/firewire/firewirereg.h @@ -368,5 +368,11 @@ extern devclass_t firewire_devclass; #define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va)) #endif /* __alpha__ */ +#if __FreeBSD_version >= 500000 +#define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */) +#else +#define CALLOUT_INIT(x) callout_init(x) +#endif + MALLOC_DECLARE(M_FW); MALLOC_DECLARE(M_FWXFER); diff --git a/sys/dev/firewire/fwdev.c b/sys/dev/firewire/fwdev.c index a85db14..a25af15 100644 --- a/sys/dev/firewire/fwdev.c +++ b/sys/dev/firewire/fwdev.c @@ -921,13 +921,21 @@ fw_poll(dev_t dev, int events, fw_proc *td) } static int +#if __FreeBSD_version < 500000 +fw_mmap (dev_t dev, vm_offset_t offset, int nproto) +#else fw_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto) +#endif { struct firewire_softc *fc; int unit = DEV2UNIT(dev); if (DEV_FWMEM(dev)) +#if __FreeBSD_version < 500000 + return fwmem_mmap(dev, offset, nproto); +#else return fwmem_mmap(dev, offset, paddr, nproto); +#endif fc = devclass_get_softc(firewire_devclass, unit); diff --git a/sys/dev/firewire/fwmem.c b/sys/dev/firewire/fwmem.c index 9c64fdc..182ea6a 100644 --- a/sys/dev/firewire/fwmem.c +++ b/sys/dev/firewire/fwmem.c @@ -419,7 +419,11 @@ fwmem_poll (dev_t dev, int events, fw_proc *td) return EINVAL; } int +#if __FreeBSD_version < 500000 +fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto) +#else fwmem_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto) +#endif { return EINVAL; } diff --git a/sys/dev/firewire/sbp.c b/sys/dev/firewire/sbp.c index b4c157b..bc0bd39 100644 --- a/sys/dev/firewire/sbp.c +++ b/sys/dev/firewire/sbp.c @@ -68,20 +68,32 @@ #define ccb_sdev_ptr spriv_ptr0 #define ccb_sbp_ptr spriv_ptr1 -#define SBP_NUM_TARGETS 8 +#define SBP_NUM_TARGETS 8 /* MAX 64 */ #define SBP_NUM_LUNS 8 /* limited by CAM_SCSI2_MAXLUN in cam_xpt.c */ #define SBP_QUEUE_LEN 4 #define SBP_NUM_OCB (SBP_QUEUE_LEN * SBP_NUM_TARGETS) #define SBP_INITIATOR 7 -#define SBP_ESELECT_TIMEOUT 1 + +#define LOGIN_DELAY 2 + +/* + * STATUS FIFO addressing + * bit + * ----------------------- + * 0- 1( 2): 0 (alingment) + * 2- 7( 6): target + * 8-15( 8): lun + * 16-23( 8): unit + * 24-31( 8): reserved + * 32-47(16): SBP_BIND_HI + * 48-64(16): bus_id, node_id + */ #define SBP_BIND_HI 0x1 -#define SBP_DEV2ADDR(u, t, l) \ +#define SBP_DEV2ADDR(u, t, l) \ ((((u) & 0xff) << 16) | (((l) & 0xff) << 8) | (((t) & 0x3f) << 2)) #define SBP_ADDR2TRG(a) (((a) >> 2) & 0x3f) #define SBP_ADDR2LUN(a) (((a) >> 8) & 0xff) -#define MAX_FREEZE 10 - #define ORB_NOTIFY (1 << 31) #define ORB_FMT_STD (0 << 29) #define ORB_FMT_VED (2 << 29) @@ -106,6 +118,7 @@ #define ORB_FUN_LUR (0xe << 16) #define ORB_FUN_RST (0xf << 16) #define ORB_FUN_MSK (0xf << 16) +#define ORB_FUN_RUNQUEUE 0xffff static char *orb_fun_name[] = { /* 0 */ "LOGIN", @@ -168,8 +181,8 @@ struct sbp_ocb { #define OCB_ACT_MASK 3 #define OCB_RESERVED 0x10 #define OCB_DONE 0x20 +#define OCB_MATCH(o,s) (vtophys(&(o)->orb[0]) == ntohl((s)->orb_lo)) -#define SBP_RESOURCE_SHORTAGE 0x10 struct sbp_login_res{ u_int16_t len; @@ -225,9 +238,11 @@ struct sbp_dev{ flags:4; u_int8_t type; u_int16_t lun_id; + int freeze; struct cam_path *path; struct sbp_target *target; struct sbp_login_res login; + struct callout login_callout; STAILQ_HEAD(, sbp_ocb) ocbs; char vendor[32]; char product[32]; @@ -241,17 +256,24 @@ struct sbp_target { struct sbp_softc *sbp; struct fw_device *fwdev; u_int32_t mgm_hi, mgm_lo; + struct sbp_ocb *mgm_ocb_cur; + STAILQ_HEAD(, sbp_ocb) mgm_ocb_queue; + struct callout mgm_ocb_timeout; +#define SCAN_DELAY 2 + struct callout scan_callout; }; struct sbp_softc { struct firewire_dev_comm fd; - unsigned char flags; struct cam_sim *sim; + struct cam_path *path; struct sbp_target targets[SBP_NUM_TARGETS]; struct fw_bind fwb; STAILQ_HEAD(, sbp_ocb) free_ocbs; struct sbp_ocb *ocb; bus_dma_tag_t dmat; +#define SBP_RESOURCE_SHORTAGE 0x10 + unsigned char flags; }; static void sbp_post_explore __P((void *)); static void sbp_recv __P((struct fw_xfer *)); @@ -265,19 +287,21 @@ static void sbp_abort_all_ocbs __P((struct sbp_dev *, int)); static struct fw_xfer * sbp_write_cmd __P((struct sbp_dev *, int, int)); static struct sbp_ocb * sbp_get_ocb __P((struct sbp_softc *)); static struct sbp_ocb * sbp_enqueue_ocb __P((struct sbp_dev *, struct sbp_ocb *)); -static struct sbp_ocb * sbp_dequeue_ocb __P((struct sbp_dev *, u_int32_t)); +static struct sbp_ocb * sbp_dequeue_ocb __P((struct sbp_dev *, struct sbp_status *)); static void sbp_cam_detach_target __P((struct sbp_target *)); static void sbp_timeout __P((void *arg)); -static void sbp_mgm_orb __P((struct sbp_dev *, int, u_int16_t, u_int32_t)); +static void sbp_mgm_orb __P((struct sbp_dev *, int, struct sbp_ocb *)); +#define sbp_login(sdev) \ + callout_reset(&(sdev)->login_callout, LOGIN_DELAY * hz, \ + sbp_login_callout, (void *)(sdev)); MALLOC_DEFINE(M_SBP, "sbp", "SBP-II/FireWire"); /* cam related functions */ static void sbp_action(struct cam_sim *sim, union ccb *ccb); static void sbp_poll(struct cam_sim *sim); -static void sbp_cam_callback(struct cam_periph *periph, - union ccb *ccb); -static void sbp_cam_scan_lun(struct sbp_dev *sdev); +static void sbp_cam_scan_lun(struct cam_periph *, union ccb *); +static void sbp_cam_scan_target(void *arg); static char *orb_status0[] = { /* 0 */ "No additional information to report", @@ -352,6 +376,9 @@ END_DEBUG } device_set_desc(dev, "SBP2/SCSI over firewire"); + + if (bootverbose) + debug = bootverbose; return (0); } @@ -469,6 +496,11 @@ END_DEBUG } target->mgm_hi = 0xffff; target->mgm_lo = 0xf0000000 | target->mgm_lo << 2; + target->mgm_ocb_cur = NULL; + STAILQ_INIT(&target->mgm_ocb_queue); + CALLOUT_INIT(&target->mgm_ocb_timeout); + CALLOUT_INIT(&target->scan_callout); + /* XXX num_lun may be changed. realloc luns? */ crom_init_context(&cc, target->fwdev->csrrom); /* XXX shoud parse appropriate unit directories only */ @@ -498,6 +530,7 @@ END_DEBUG sdev->lun_id = i; sdev->target = target; STAILQ_INIT(&sdev->ocbs); + CALLOUT_INIT(&sdev->login_callout); sdev->status = SBP_DEV_DEAD; } crom_init_context(&cc, target->fwdev->csrrom); @@ -565,14 +598,30 @@ sbp_probe_lun(struct sbp_dev *sdev) rev = getcsrdata(sdev->target->fwdev, 0x3c); snprintf(sdev->revision, sizeof(sdev->revision), "%06x", rev); } + + +static void +sbp_login_callout(void *arg) +{ + struct sbp_dev *sdev = (struct sbp_dev *)arg; + sbp_mgm_orb(sdev, ORB_FUN_LGI, NULL); +} + +#define SBP_FWDEV_ALIVE(fwdev) \ + ((fwdev->status == FWDEVATTACHED) \ + && (getcsrdata(fwdev, CSRKEY_SPEC) == CSRVAL_ANSIT10) \ + && (getcsrdata(fwdev, CSRKEY_VER) == CSRVAL_T10SBP2)) + static void -sbp_probe_target(struct sbp_target *target, int alive) +sbp_probe_target(void *arg) { + struct sbp_target *target = (struct sbp_target *)arg; struct sbp_softc *sbp; struct sbp_dev *sdev; struct firewire_comm *fc; - int i; + int i, alive; + alive = SBP_FWDEV_ALIVE(target->fwdev); SBP_DEBUG(1) printf("sbp_probe_target %d\n", target->target_id); if (!alive) @@ -581,32 +630,43 @@ END_DEBUG sbp = target->sbp; fc = target->sbp->fd.fc; + /* XXX untimeout mgm_ocb and dequeue */ for (i=0; i < target->num_lun; i++) { sdev = &target->luns[i]; if (alive && (sdev->status != SBP_DEV_DEAD)) { if (sdev->path != NULL) { xpt_freeze_devq(sdev->path, 1); + sdev->freeze ++; } - sbp_abort_all_ocbs(sdev, CAM_REQUEUE_REQ); + sbp_probe_lun(sdev); +SBP_DEBUG(0) + sbp_show_sdev_info(sdev, +#if 0 + (sdev->status == SBP_DEV_TOATTACH)); +#else + (sdev->status == SBP_DEV_RESET)); +#endif +END_DEBUG + + sbp_abort_all_ocbs(sdev, CAM_SCSI_BUS_RESET); switch (sdev->status) { case SBP_DEV_RESET: /* new or revived target */ - sbp_probe_lun(sdev); if (auto_login) { +#if 0 sdev->status = SBP_DEV_TOATTACH; - sbp_mgm_orb(sdev, ORB_FUN_LGI, 0, 0); +#endif + sbp_login(sdev); } break; + case SBP_DEV_TOATTACH: + case SBP_DEV_PROBE: + case SBP_DEV_ATTACHED: case SBP_DEV_RETRY: - sbp_probe_lun(sdev); default: - sbp_mgm_orb(sdev, ORB_FUN_RCN, 0, 0); + sbp_mgm_orb(sdev, ORB_FUN_RCN, NULL); break; } -SBP_DEBUG(0) - sbp_show_sdev_info(sdev, - (sdev->status == SBP_DEV_TOATTACH)); -END_DEBUG } else { switch (sdev->status) { case SBP_DEV_ATTACHED: @@ -615,10 +675,12 @@ SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("lost target\n"); END_DEBUG - if (sdev->path) + if (sdev->path) { xpt_freeze_devq(sdev->path, 1); + sdev->freeze ++; + } sdev->status = SBP_DEV_RETRY; - sbp_abort_all_ocbs(sdev, CAM_REQUEUE_REQ); + sbp_abort_all_ocbs(sdev, CAM_SCSI_BUS_RESET); break; case SBP_DEV_PROBE: case SBP_DEV_TOATTACH: @@ -644,11 +706,15 @@ sbp_post_explore(void *arg) SBP_DEBUG(0) printf("sbp_post_explore (sbp_cold=%d)\n", sbp_cold); END_DEBUG -#if 0 - xpt_freeze_simq(sbp->sim, /*count*/ 1); +#if 0 /* + * XXX don't let CAM the bus rest. CAM tries to do something with + * freezed (DEV_RETRY) devices + */ + xpt_async(AC_BUS_RESET, sbp->path, /*arg*/ NULL); #endif if (sbp_cold > 0) sbp_cold --; + /* Gabage Collection */ for(i = 0 ; i < SBP_NUM_TARGETS ; i ++){ target = &sbp->targets[i]; @@ -678,9 +744,7 @@ SBP_DEBUG(0) printf("not attached, state=%d.\n", fwdev->status); } END_DEBUG - alive = (fwdev->status == FWDEVATTACHED) - && (getcsrdata(fwdev, CSRKEY_SPEC) == CSRVAL_ANSIT10) - && (getcsrdata(fwdev, CSRKEY_VER) == CSRVAL_T10SBP2); + alive = SBP_FWDEV_ALIVE(fwdev); for(i = 0 ; i < SBP_NUM_TARGETS ; i ++){ target = &sbp->targets[i]; if(target->fwdev == fwdev ) { @@ -698,7 +762,7 @@ END_DEBUG continue; } } - sbp_probe_target(target, alive); + sbp_probe_target((void *)target); } #if 0 timeout(sbp_release_queue, (caddr_t)sbp, bus_reset_rest * hz / 1000); @@ -745,46 +809,91 @@ END_DEBUG return; } +static struct sbp_dev * +sbp_next_dev(struct sbp_target *target, int lun) +{ + struct sbp_dev *sdev; + int i; + + for (i = lun, sdev = &target->luns[lun]; + i < target->num_lun; i++, sdev++) { + if (sdev->status == SBP_DEV_PROBE) + break; + } + if (i >= target->num_lun) + return(NULL); + return(sdev); +} + +#define SCAN_PRI 1 static void -sbp_cam_callback(struct cam_periph *periph, union ccb *ccb) +sbp_cam_scan_lun(struct cam_periph *periph, union ccb *ccb) { + struct sbp_target *target; struct sbp_dev *sdev; + sdev = (struct sbp_dev *) ccb->ccb_h.ccb_sdev_ptr; + target = sdev->target; SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); - printf("sbp_cam_callback\n"); + printf("sbp_cam_scan_lun\n"); END_DEBUG - sdev->status = SBP_DEV_ATTACHED; - free(ccb, M_SBP); + if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { + sdev->status = SBP_DEV_ATTACHED; + } else { + sbp_show_sdev_info(sdev, 2); + printf("scan failed\n"); + } + sdev = sbp_next_dev(target, sdev->lun_id + 1); + if (sdev == NULL) { + free(ccb, M_SBP); + return; + } + /* reuse ccb */ + xpt_setup_ccb(&ccb->ccb_h, sdev->path, SCAN_PRI); + ccb->ccb_h.ccb_sdev_ptr = sdev; + xpt_action(ccb); + xpt_release_devq(sdev->path, sdev->freeze, TRUE); + sdev->freeze = 1; } static void -sbp_cam_scan_lun(struct sbp_dev *sdev) +sbp_cam_scan_target(void *arg) { + struct sbp_target *target = (struct sbp_target *)arg; + struct sbp_dev *sdev; union ccb *ccb; - ccb = malloc(sizeof(union ccb), M_SBP, M_NOWAIT | M_ZERO); - if (ccb == NULL) { - printf("sbp_cam_scan_lun: malloc failed\n"); + sdev = sbp_next_dev(target, 0); + if (sdev == NULL) { + printf("sbp_cam_scan_target: nothing to do for target%d\n", + target->target_id); return; } - SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); - printf("sbp_cam_scan_lun\n"); + printf("sbp_cam_scan_target\n"); END_DEBUG - xpt_setup_ccb(&ccb->ccb_h, sdev->path, 5/*priority (low)*/); + ccb = malloc(sizeof(union ccb), M_SBP, M_NOWAIT | M_ZERO); + if (ccb == NULL) { + printf("sbp_cam_scan_target: malloc failed\n"); + return; + } + xpt_setup_ccb(&ccb->ccb_h, sdev->path, SCAN_PRI); ccb->ccb_h.func_code = XPT_SCAN_LUN; - ccb->ccb_h.cbfcnp = sbp_cam_callback; + ccb->ccb_h.cbfcnp = sbp_cam_scan_lun; + ccb->ccb_h.flags |= CAM_DEV_QFREEZE; ccb->crcn.flags = CAM_FLAG_NONE; ccb->ccb_h.ccb_sdev_ptr = sdev; /* The scan is in progress now. */ - sdev->status = SBP_DEV_PROBE; xpt_action(ccb); + xpt_release_devq(sdev->path, sdev->freeze, TRUE); + sdev->freeze = 1; } +#if 0 static void sbp_ping_unit_callback(struct cam_periph *periph, union ccb *ccb) { @@ -804,13 +913,15 @@ END_DEBUG } else { /* requeue */ xpt_action(ccb); - xpt_release_devq(sdev->path, MAX_FREEZE, TRUE); + xpt_release_devq(sdev->path, sdev->freeze, TRUE); + sdev->freeze = 1; /* we will freeze */ } } else { free(ccb->csio.data_ptr, M_SBP); free(ccb, M_SBP); sdev->status = SBP_DEV_ATTACHED; - xpt_release_devq(sdev->path, MAX_FREEZE, TRUE); + xpt_release_devq(sdev->path, sdev->freeze, TRUE); + sdev->freeze = 0; } } @@ -850,7 +961,7 @@ END_DEBUG /* * We need to execute this command before any other queued command. - * Make priority 0 and freeze queue after execution for retry. + * Make priority 0 and freeze the queue after execution for retry. * cam's scan_lun command doesn't provide this feature. */ xpt_setup_ccb(&ccb->ccb_h, sdev->path, 0/*priority (high)*/); @@ -867,16 +978,33 @@ END_DEBUG /*timeout*/60000 ); ccb->ccb_h.flags |= CAM_DEV_QFREEZE; + ccb->ccb_h.ccb_sdev_ptr = sdev; xpt_action(ccb); + if (sdev->status != SBP_DEV_ATTACHED) + sdev->status = SBP_DEV_PROBE; + xpt_release_devq(sdev->path, sdev->freeze, TRUE); + sdev->freeze = 1; /* We will freeze the queue */ +} +#endif + +static __inline void +sbp_scan_dev(struct sbp_dev *sdev) +{ sdev->status = SBP_DEV_PROBE; + callout_reset(&sdev->target->scan_callout, SCAN_DELAY * hz, + sbp_cam_scan_target, (void *)sdev->target); } static void sbp_do_attach(struct fw_xfer *xfer) { struct sbp_dev *sdev; + struct sbp_target *target; + struct sbp_softc *sbp; sdev = (struct sbp_dev *)xfer->sc; + target = sdev->target; + sbp = target->sbp; SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("sbp_do_attach\n"); @@ -885,8 +1013,8 @@ END_DEBUG if (sdev->path == NULL) xpt_create_path(&sdev->path, xpt_periph, - cam_sim_path(sdev->target->sbp->sim), - sdev->target->target_id, sdev->lun_id); + cam_sim_path(target->sbp->sim), + target->target_id, sdev->lun_id); /* * Let CAM scan the bus if we are in the boot process. @@ -894,15 +1022,11 @@ END_DEBUG * if LUN 0 doesn't exists. */ if (sbp_cold > 0) { - sdev->status = SBP_DEV_PROBE; + sdev->status = SBP_DEV_ATTACHED; return; } - if (sdev->status == SBP_DEV_RETRY) - sbp_ping_unit(sdev); - else - sbp_cam_scan_lun(sdev); - xpt_release_devq(sdev->path, MAX_FREEZE, TRUE); + sbp_scan_dev(sdev); return; } @@ -917,9 +1041,10 @@ SBP_DEBUG(1) printf("sbp_cmd_callback\n"); END_DEBUG fw_xfer_free(xfer); - sbp_abort_all_ocbs(sdev, CAM_REQUEUE_REQ); - if (sdev->path) - xpt_release_devq(sdev->path, MAX_FREEZE, TRUE); + if (sdev->path) { + xpt_release_devq(sdev->path, sdev->freeze, TRUE); + sdev->freeze = 0; + } } static void @@ -942,6 +1067,7 @@ END_DEBUG fp = (struct fw_pkt *)xfer->send.buf; fp->mode.wreqq.data = htonl(0xf); fw_asyreq(xfer->fc, -1, xfer); + sbp_abort_all_ocbs(sdev, CAM_BDR_SENT); } static void @@ -1088,29 +1214,40 @@ sbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset) } static void -sbp_mgm_orb(struct sbp_dev *sdev, int func, u_int16_t orb_hi, u_int32_t orb_lo) +sbp_mgm_orb(struct sbp_dev *sdev, int func, struct sbp_ocb *aocb) { struct fw_xfer *xfer; struct fw_pkt *fp; struct sbp_ocb *ocb; + struct sbp_target *target; int s, nid; - if ((ocb = sbp_get_ocb(sdev->target->sbp)) == NULL) { - s = splfw(); - sdev->target->sbp->flags |= SBP_RESOURCE_SHORTAGE; + target = sdev->target; + nid = target->sbp->fd.fc->nodeid | FWLOCALBUS; + + s = splfw(); + if (func == ORB_FUN_RUNQUEUE) { + ocb = STAILQ_FIRST(&target->mgm_ocb_queue); + if (target->mgm_ocb_cur != NULL || ocb == NULL) { + splx(s); + return; + } + STAILQ_REMOVE_HEAD(&target->mgm_ocb_queue, ocb); + goto start; + } + if ((ocb = sbp_get_ocb(target->sbp)) == NULL) { + target->sbp->flags |= SBP_RESOURCE_SHORTAGE; splx(s); return; } ocb->flags = OCB_ACT_MGM; ocb->sdev = sdev; - ocb->ccb = NULL; - nid = sdev->target->sbp->fd.fc->nodeid | FWLOCALBUS; bzero((void *)(uintptr_t)(volatile void *)ocb->orb, sizeof(ocb->orb)); ocb->orb[6] = htonl((nid << 16) | SBP_BIND_HI); ocb->orb[7] = htonl(SBP_DEV2ADDR( - device_get_unit(sdev->target->sbp->fd.dev), - sdev->target->target_id, + device_get_unit(target->sbp->fd.dev), + target->target_id, sdev->lun_id)); SBP_DEBUG(0) @@ -1125,8 +1262,8 @@ END_DEBUG ocb->orb[5] = htonl(sizeof(struct sbp_login_res)); break; case ORB_FUN_ATA: - ocb->orb[0] = htonl((0 << 16) | orb_hi); - ocb->orb[1] = htonl(orb_lo); + ocb->orb[0] = htonl((0 << 16) | 0); + ocb->orb[1] = htonl(vtophys(&aocb->orb[0])); /* fall through */ case ORB_FUN_RCN: case ORB_FUN_LGO: @@ -1137,6 +1274,18 @@ END_DEBUG break; } + if (target->mgm_ocb_cur != NULL) { + /* there is a standing ORB */ + STAILQ_INSERT_TAIL(&sdev->target->mgm_ocb_queue, ocb, ocb); + splx(s); + return; + } +start: + target->mgm_ocb_cur = ocb; + splx(s); + + callout_reset(&target->mgm_ocb_timeout, 5*hz, + sbp_timeout, (caddr_t)ocb); xfer = sbp_write_cmd(sdev, FWTCODE_WREQB, 0); if(xfer == NULL){ return; @@ -1150,7 +1299,6 @@ END_DEBUG fp->mode.wreqb.extcode = 0; fp->mode.wreqb.payload[0] = htonl(nid << 16); fp->mode.wreqb.payload[1] = htonl(vtophys(&ocb->orb[0])); - sbp_enqueue_ocb(sdev, ocb); fw_asyreq(xfer->fc, -1, xfer); } @@ -1314,15 +1462,19 @@ END_DEBUG #endif /* fall through */ case T_RBC: - /* disable tag queuing */ - inq->flags &= ~SID_CmdQue; + /* enable tag queuing */ +#if 1 + inq->flags |= SID_CmdQue; +#endif /* * Override vendor/product/revision information. * Some devices sometimes return strange strings. */ +#if 1 bcopy(sdev->vendor, inq->vendor, sizeof(inq->vendor)); bcopy(sdev->product, inq->product, sizeof(inq->product)); bcopy(sdev->revision+2, inq->revision, sizeof(inq->revision)); +#endif break; } } @@ -1339,7 +1491,7 @@ sbp_recv1(struct fw_xfer *xfer){ struct sbp_login_res *login_res = NULL; struct sbp_status *sbp_status; struct sbp_target *target; - int orb_fun, status_valid, t, l; + int orb_fun, status_valid0, status_valid, t, l; u_int32_t addr; /* u_int32_t *ld; @@ -1392,7 +1544,16 @@ END_DEBUG switch (sbp_status->src) { case 0: case 1: - ocb = sbp_dequeue_ocb(sdev, ntohl(sbp_status->orb_lo)); + /* check mgm_ocb_cur first */ + ocb = target->mgm_ocb_cur; + if (ocb != NULL) { + if (OCB_MATCH(ocb, sbp_status)) { + callout_stop(&target->mgm_ocb_timeout); + target->mgm_ocb_cur = NULL; + break; + } + } + ocb = sbp_dequeue_ocb(sdev, sbp_status); if (ocb == NULL) { sbp_show_sdev_info(sdev, 2); printf("No ocb on the queue\n"); @@ -1408,12 +1569,12 @@ END_DEBUG printf("unknown sbp_status->src\n"); } - status_valid = (sbp_status->src < 2 + status_valid0 = (sbp_status->src < 2 && sbp_status->resp == ORB_RES_CMPL - && sbp_status->dead == 0 - && sbp_status->status == 0); + && sbp_status->dead == 0); + status_valid = (status_valid0 && sbp_status->status == 0); - if (!status_valid || debug > 1){ + if (!status_valid0 || debug > 1){ int status; SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); @@ -1454,8 +1615,10 @@ END_DEBUG /* we have to reset the fetch agent if it's dead */ if (sbp_status->dead) { - if (sdev->path) + if (sdev->path) { xpt_freeze_devq(sdev->path, 1); + sdev->freeze ++; + } sbp_agent_reset(sdev); } @@ -1487,10 +1650,13 @@ SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("login: len %d, ID %d, cmd %08x%08x, recon_hold %d\n", login_res->len, login_res->id, login_res->cmd_hi, login_res->cmd_lo, ntohs(login_res->recon_hold)); END_DEBUG +#if 0 + sdev->status = SBP_DEV_TOATTACH; +#endif #if 1 sbp_busy_timeout(sdev); #else - sbp_mgm_orb(sdev, ORB_FUN_ATS, 0, 0); + sbp_mgm_orb(sdev, ORB_FUN_ATS, NULL); #endif } else { /* forgot logout? */ @@ -1507,12 +1673,13 @@ sbp_show_sdev_info(sdev, 2); printf("reconnect: len %d, ID %d, cmd %08x%08x\n", login_res->len, login_res->id, login_res->cmd_hi, login_res->cmd_lo); END_DEBUG #if 1 - sbp_ping_unit(sdev); - xpt_release_devq(sdev->path, - MAX_FREEZE, TRUE); + if (sdev->status == SBP_DEV_ATTACHED) + sbp_scan_dev(sdev); + else + sbp_agent_reset(sdev); #else sdev->status = SBP_DEV_ATTACHED; - sbp_mgm_orb(sdev, ORB_FUN_ATS, 0, 0); + sbp_mgm_orb(sdev, ORB_FUN_ATS, NULL); #endif } else { /* reconnection hold time exceed? */ @@ -1520,7 +1687,7 @@ SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("reconnect failed\n"); END_DEBUG - sbp_mgm_orb(sdev, ORB_FUN_LGI, 0, 0); + sbp_login(sdev); } break; case ORB_FUN_LGO: @@ -1539,6 +1706,7 @@ END_DEBUG printf("unknown function %d\n", orb_fun); break; } + sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL); break; case OCB_ACT_CMD: if(ocb->ccb != NULL){ @@ -1664,8 +1832,9 @@ END_DEBUG sbp->sim = cam_sim_alloc(sbp_action, sbp_poll, "sbp", sbp, device_get_unit(dev), - /*untagged*/ SBP_QUEUE_LEN, - /*tagged*/0, devq); + /*untagged*/ 1, + /*tagged*/ SBP_QUEUE_LEN, + devq); if (sbp->sim == NULL) { cam_simq_free(devq); @@ -1687,12 +1856,12 @@ END_DEBUG sbp_free_ocb(sbp, &sbp->ocb[i]); } - if (xpt_bus_register(sbp->sim, /*bus*/0) != CAM_SUCCESS) { - cam_sim_free(sbp->sim, /*free_devq*/TRUE); - contigfree(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB, - M_SBP); - return (ENXIO); - } + if (xpt_bus_register(sbp->sim, /*bus*/0) != CAM_SUCCESS) + goto fail; + + if (xpt_create_path(&sbp->path, xpt_periph, cam_sim_path(sbp->sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) + goto fail; xfer = fw_xfer_alloc(M_SBP); xfer->act.hand = sbp_recv; @@ -1718,6 +1887,10 @@ END_DEBUG } return (0); +fail: + cam_sim_free(sbp->sim, /*free_devq*/TRUE); + contigfree(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB, M_SBP); + return (ENXIO); } static int @@ -1738,7 +1911,7 @@ END_DEBUG sdev = &target->luns[j]; if (sdev->status >= SBP_DEV_TOATTACH && sdev->status <= SBP_DEV_ATTACHED) - sbp_mgm_orb(sdev, ORB_FUN_LGO, 0, 0); + sbp_mgm_orb(sdev, ORB_FUN_LGO, NULL); } } return 0; @@ -1771,6 +1944,7 @@ END_DEBUG for (i = 0; i < SBP_NUM_TARGETS; i ++) sbp_cam_detach_target(&sbp->targets[i]); + xpt_free_path(sbp->path); xpt_bus_deregister(cam_sim_path(sbp->sim)); sbp_logout_all(sbp); @@ -1798,8 +1972,11 @@ sbp_cam_detach_target(struct sbp_target *target) SBP_DEBUG(0) printf("sbp_detach_target %d\n", target->target_id); END_DEBUG + callout_stop(&target->scan_callout); + callout_stop(&target->mgm_ocb_timeout); for (i = 0; i < target->num_lun; i++) { sdev = &target->luns[i]; + callout_stop(&sdev->login_callout); if (sdev->status == SBP_DEV_RESET || sdev->status == SBP_DEV_DEAD) continue; @@ -1822,7 +1999,16 @@ sbp_timeout(void *arg) sbp_show_sdev_info(sdev, 2); printf("request timeout ... "); + if (ocb->flags == OCB_ACT_MGM) { + printf("management ORB\n"); + /* XXX just ignore for now */ + sdev->target->mgm_ocb_cur = NULL; + sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL); + return; + } + xpt_freeze_devq(sdev->path, 1); + sdev->freeze ++; sbp_abort_all_ocbs(sdev, CAM_CMD_TIMEOUT); if (sdev->flags & SBP_DEV_TIMEOUT) { #if 0 @@ -1834,7 +2020,7 @@ sbp_timeout(void *arg) sdev->status == SBP_DEV_RETRY; #else printf("target reset\n"); - sbp_mgm_orb(sdev, ORB_FUN_RST, 0, 0); + sbp_mgm_orb(sdev, ORB_FUN_RST, NULL); #endif sdev->flags &= ~SBP_DEV_TIMEOUT; } else { @@ -2086,7 +2272,7 @@ SBP_DEBUG(1) ccb->ccb_h.target_id, ccb->ccb_h.target_lun); END_DEBUG cpi->version_num = 1; /* XXX??? */ - cpi->hba_inquiry = 0; + cpi->hba_inquiry = PI_TAG_ABLE; cpi->target_sprt = 0; cpi->hba_misc = PIM_NOBUSRESET; cpi->hba_eng_cnt = 0; @@ -2112,9 +2298,9 @@ SBP_DEBUG(1) device_get_nameunit(sbp->fd.dev), ccb->ccb_h.target_id, ccb->ccb_h.target_lun); END_DEBUG - /* Disable disconnect and tagged queuing */ + /* Enable disconnect and tagged queuing */ cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; - cts->flags = 0; + cts->flags = CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB; cts->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); @@ -2124,6 +2310,8 @@ END_DEBUG ccb->ccb_h.status = CAM_UA_ABORT; xpt_done(ccb); break; + case XPT_SET_TRAN_SETTINGS: + /* XXX */ default: ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); @@ -2206,7 +2394,7 @@ sbp_poll(struct cam_sim *sim) return; } static struct sbp_ocb * -sbp_dequeue_ocb(struct sbp_dev *sdev, u_int32_t orb_lo) +sbp_dequeue_ocb(struct sbp_dev *sdev, struct sbp_status *sbp_status) { struct sbp_ocb *ocb; struct sbp_ocb *next; @@ -2225,7 +2413,7 @@ SBP_DEBUG(1) #endif vtophys(&ocb->orb[0]), ntohl(ocb->orb[1]), flags); END_DEBUG - if (vtophys(&ocb->orb[0]) == orb_lo) { + if (OCB_MATCH(ocb, sbp_status)) { /* found */ if (ocb->flags & OCB_RESERVED) ocb->flags |= OCB_DONE; @@ -2309,7 +2497,7 @@ sbp_get_ocb(struct sbp_softc *sbp) printf("ocb shortage!!!\n"); return NULL; } - STAILQ_REMOVE(&sbp->free_ocbs, ocb, sbp_ocb, ocb); + STAILQ_REMOVE_HEAD(&sbp->free_ocbs, ocb); splx(s); ocb->ccb = NULL; return (ocb); |