summaryrefslogtreecommitdiffstats
path: root/sys/cam/cam_periph.c
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1999-05-22 21:58:47 +0000
committergibbs <gibbs@FreeBSD.org>1999-05-22 21:58:47 +0000
commit95dc85b099eb4f732b322f090ce0abad1280fbfd (patch)
tree84ee71641db91cb247029bd5aa2d5bffd89b16dd /sys/cam/cam_periph.c
parente4dc7e4c0e6535e2f3849d8c0335cbd9e6f86379 (diff)
downloadFreeBSD-src-95dc85b099eb4f732b322f090ce0abad1280fbfd.zip
FreeBSD-src-95dc85b099eb4f732b322f090ce0abad1280fbfd.tar.gz
Add the XPT_PATH_STATS and XPT_GDEV_STATS function codes. These ccb
types allow the reporting of error counts and other statistics. Currently we provide information on the last BDR or bus reset as well as active transaction inforamtion, but this will be expanded as more information is added to aid in error recovery. Use the 'last reset' information to better handle bus settle delays. Peripheral drivers now control whether a bus settle delay occurs and for how long. This allows target mode peripheral drivers to avoid having their device queue frozen by the XPT for what shoudl only be initiator type behavior. Don't perform a bus reset if the target device is incapable of performing transfer negotiation (e.g. Fiber Channel). If we don't perform a bus reset but the controller is capable of transfer negotiations, force negotiations on the first transaction to go to the device. This ensures that we aren't tripped up by a left over negotiation from the prom, BIOS, loader, etc. Add a default async handler funstion to cam_periph.c to remove duplicated code in all initiator type peripheral drivers. Allow mapping of XPT_CONT_TARGET_IO ccbs from userland. They are itentical to XPT_SCSI_IO ccbs as far as data mapping is concerned.
Diffstat (limited to 'sys/cam/cam_periph.c')
-rw-r--r--sys/cam/cam_periph.c78
1 files changed, 77 insertions, 1 deletions
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index d365a12..f88373b 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: cam_periph.c,v 1.12 1999/04/19 21:26:07 gibbs Exp $
+ * $Id: cam_periph.c,v 1.13 1999/05/09 01:25:04 ken Exp $
*/
#include <sys/param.h>
@@ -519,6 +519,7 @@ cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
}
break;
case XPT_SCSI_IO:
+ case XPT_CONT_TARGET_IO:
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE)
return(0);
@@ -834,6 +835,17 @@ cam_periph_runccb(union ccb *ccb,
return(error);
}
+void
+cam_freeze_devq(struct cam_path *path)
+{
+ struct ccb_hdr ccb_h;
+
+ xpt_setup_ccb(&ccb_h, path, /*priority*/1);
+ ccb_h.func_code = XPT_NOOP;
+ ccb_h.flags = CAM_DEV_QFREEZE;
+ xpt_action((union ccb *)&ccb_h);
+}
+
u_int32_t
cam_release_devq(struct cam_path *path, u_int32_t relsim_flags,
u_int32_t openings, u_int32_t timeout,
@@ -1015,6 +1027,70 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
}
/*
+ * Generic Async Event handler. Peripheral drivers usually
+ * filter out the events that require personal attention,
+ * and leave the rest to this function.
+ */
+void
+cam_periph_async(struct cam_periph *periph, u_int32_t code,
+ struct cam_path *path, void *arg)
+{
+ switch (code) {
+ case AC_LOST_DEVICE:
+ cam_periph_invalidate(periph);
+ break;
+ case AC_SENT_BDR:
+ case AC_BUS_RESET:
+ {
+ cam_periph_bus_settle(periph, SCSI_DELAY);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void
+cam_periph_bus_settle(struct cam_periph *periph, u_int bus_settle)
+{
+ struct ccb_getdevstats cgds;
+
+ xpt_setup_ccb(&cgds.ccb_h, periph->path, /*priority*/1);
+ cgds.ccb_h.func_code = XPT_GDEV_STATS;
+ xpt_action((union ccb *)&cgds);
+ cam_periph_freeze_after_event(periph, &cgds.last_reset, bus_settle);
+}
+
+void
+cam_periph_freeze_after_event(struct cam_periph *periph,
+ struct timeval* event_time, u_int duration_ms)
+{
+ struct timeval delta;
+ struct timeval duration_tv;
+ int s;
+
+ s = splclock();
+ microtime(&delta);
+ splx(s);
+ timevalsub(&delta, event_time);
+ duration_tv.tv_sec = duration_ms / 1000;
+ duration_tv.tv_usec = (duration_ms % 1000) * 1000;
+ if (timevalcmp(&delta, &duration_tv, <)) {
+ timevalsub(&duration_tv, &delta);
+
+ duration_ms = duration_tv.tv_sec * 1000;
+ duration_ms += duration_tv.tv_usec / 1000;
+ cam_freeze_devq(periph->path);
+ cam_release_devq(periph->path,
+ RELSIM_RELEASE_AFTER_TIMEOUT,
+ /*reduction*/0,
+ /*timeout*/duration_ms,
+ /*getcount_only*/0);
+ }
+
+}
+
+/*
* Generic error handler. Peripheral drivers usually filter
* out the errors that they handle in a unique mannor, then
* call this function.
OpenPOWER on IntegriCloud