summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/cam/cam_periph.c105
1 files changed, 103 insertions, 2 deletions
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index 625be21..d8940a0 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -86,6 +86,7 @@ static int camperiphscsisenseerror(union ccb *ccb,
u_int32_t *timeout,
u_int32_t *action,
const char **action_string);
+static void cam_periph_devctl_notify(union ccb *ccb);
static int nperiph_drivers;
static int initialized = 0;
@@ -1615,7 +1616,7 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
struct cam_periph *periph;
const char *action_string;
cam_status status;
- int frozen, error, openings;
+ int frozen, error, openings, devctl_err;
u_int32_t action, relsim_flags, timeout;
action = SSQ_PRINT_SENSE;
@@ -1624,9 +1625,26 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
status = ccb->ccb_h.status;
frozen = (status & CAM_DEV_QFRZN) != 0;
status &= CAM_STATUS_MASK;
- openings = relsim_flags = timeout = 0;
+ devctl_err = openings = relsim_flags = timeout = 0;
orig_ccb = ccb;
+ /* Filter the errors that should be reported via devctl */
+ switch (ccb->ccb_h.status & CAM_STATUS_MASK) {
+ case CAM_CMD_TIMEOUT:
+ case CAM_REQ_ABORTED:
+ case CAM_REQ_CMP_ERR:
+ case CAM_REQ_TERMIO:
+ case CAM_UNREC_HBA_ERROR:
+ case CAM_DATA_RUN_ERR:
+ case CAM_SCSI_STATUS_ERROR:
+ case CAM_ATA_STATUS_ERROR:
+ case CAM_SMP_STATUS_ERROR:
+ devctl_err++;
+ break;
+ default:
+ break;
+ }
+
switch (status) {
case CAM_REQ_CMP:
error = 0;
@@ -1754,6 +1772,9 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
xpt_print(ccb->ccb_h.path, "Retrying command\n");
}
+ if (devctl_err)
+ cam_periph_devctl_notify(orig_ccb);
+
if ((action & SSQ_LOST) != 0) {
lun_id_t lun_id;
@@ -1824,3 +1845,83 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
return (error);
}
+
+#define CAM_PERIPH_DEVD_MSG_SIZE 256
+
+static void
+cam_periph_devctl_notify(union ccb *ccb)
+{
+ struct cam_periph *periph;
+ struct ccb_getdev *cgd;
+ struct sbuf sb;
+ int serr, sk, asc, ascq;
+ char *sbmsg, *type;
+
+ sbmsg = malloc(CAM_PERIPH_DEVD_MSG_SIZE, M_CAMPERIPH, M_NOWAIT);
+ if (sbmsg == NULL)
+ return;
+
+ sbuf_new(&sb, sbmsg, CAM_PERIPH_DEVD_MSG_SIZE, SBUF_FIXEDLEN);
+
+ periph = xpt_path_periph(ccb->ccb_h.path);
+ sbuf_printf(&sb, "device=%s%d ", periph->periph_name,
+ periph->unit_number);
+
+ sbuf_printf(&sb, "serial=\"");
+ if ((cgd = (struct ccb_getdev *)xpt_alloc_ccb_nowait()) != NULL) {
+ xpt_setup_ccb(&cgd->ccb_h, ccb->ccb_h.path,
+ CAM_PRIORITY_NORMAL);
+ cgd->ccb_h.func_code = XPT_GDEV_TYPE;
+ xpt_action((union ccb *)cgd);
+
+ if (cgd->ccb_h.status == CAM_REQ_CMP)
+ sbuf_bcat(&sb, cgd->serial_num, cgd->serial_num_len);
+ }
+ sbuf_printf(&sb, "\" ");
+ sbuf_printf(&sb, "cam_status=\"0x%x\" ", ccb->ccb_h.status);
+
+ switch (ccb->ccb_h.status & CAM_STATUS_MASK) {
+ case CAM_CMD_TIMEOUT:
+ sbuf_printf(&sb, "timeout=%d ", ccb->ccb_h.timeout);
+ type = "timeout";
+ break;
+ case CAM_SCSI_STATUS_ERROR:
+ sbuf_printf(&sb, "scsi_status=%d ", ccb->csio.scsi_status);
+ if (scsi_extract_sense_ccb(ccb, &serr, &sk, &asc, &ascq))
+ sbuf_printf(&sb, "scsi_sense=\"%02x %02x %02x %02x\" ",
+ serr, sk, asc, ascq);
+ type = "error";
+ break;
+ case CAM_ATA_STATUS_ERROR:
+ {
+ char res_str[(11 * 3) + 1];
+
+ sbuf_printf(&sb, "RES=\"%s\" ", ata_res_string(&ccb->ataio.res,
+ res_str, sizeof(res_str)));
+ type = "error";
+ break;
+ }
+ default:
+ type = "error";
+ break;
+ }
+
+ if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
+ sbuf_printf(&sb, "CDB=\"");
+ if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0)
+ scsi_cdb_sbuf(ccb->csio.cdb_io.cdb_ptr, &sb);
+ else
+ scsi_cdb_sbuf(ccb->csio.cdb_io.cdb_bytes, &sb);
+ sbuf_printf(&sb, "\" ");
+ } else if (ccb->ccb_h.func_code == XPT_ATA_IO) {
+ sbuf_printf(&sb, "ACB=\"");
+ ata_cmd_sbuf(&ccb->ataio.cmd, &sb);
+ sbuf_printf(&sb, "\" ");
+ }
+
+ if (sbuf_finish(&sb) == 0)
+ devctl_notify("CAM", "periph", type, sbuf_data(&sb));
+ sbuf_delete(&sb);
+ free(sbmsg, M_CAMPERIPH);
+}
+
OpenPOWER on IntegriCloud