summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2012-10-27 10:14:12 +0000
committermav <mav@FreeBSD.org>2012-10-27 10:14:12 +0000
commitdd686c1964423afe1f6f0a02fa97a39979928d53 (patch)
treeff3fc100f4f79e9d9b408c3743ae5c7fffc6f023 /sys/cam
parent1cb4a9777f389b1260f867fc5fcd261506ab8cec (diff)
downloadFreeBSD-src-dd686c1964423afe1f6f0a02fa97a39979928d53.zip
FreeBSD-src-dd686c1964423afe1f6f0a02fa97a39979928d53.tar.gz
Remove priority enforcement from xpt_ation(). It is not good and even not
safe in some cases to reduce CCB priority after it was scheduled with high priority. This fixes reproducible deadlock when command sent through the pass interface while ATA XPT recovers from command timeout. Instead of that enforce priority at passioctl(). libcam provides no obvious interface to specify CCB priority and so much (all?) code specifies zero (highest) priority. This change limits pass CCBs priority to NORMAL run level, allowing XPT to complete bus and device recovery after reset before running any payload.
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/cam.h1
-rw-r--r--sys/cam/cam_xpt.c3
-rw-r--r--sys/cam/scsi/scsi_pass.c11
3 files changed, 9 insertions, 6 deletions
diff --git a/sys/cam/cam.h b/sys/cam/cam.h
index 0f8d30e..a3e191f 100644
--- a/sys/cam/cam.h
+++ b/sys/cam/cam.h
@@ -83,6 +83,7 @@ typedef struct {
#define CAM_PRIORITY_NORMAL ((CAM_RL_NORMAL << 8) + 0x80)
#define CAM_PRIORITY_NONE (u_int32_t)-1
#define CAM_PRIORITY_TO_RL(x) ((x) >> 8)
+#define CAM_RL_TO_PRIORITY(x) ((x) << 8)
u_int32_t generation;
int index;
#define CAM_UNQUEUED_INDEX -1
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 6288390..b184dd1 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -2468,9 +2468,6 @@ xpt_action(union ccb *start_ccb)
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n"));
start_ccb->ccb_h.status = CAM_REQ_INPROG;
- /* Compatibility for RL-unaware code. */
- if (CAM_PRIORITY_TO_RL(start_ccb->ccb_h.pinfo.priority) == 0)
- start_ccb->ccb_h.pinfo.priority += CAM_PRIORITY_NORMAL - 1;
(*(start_ccb->ccb_h.path->bus->xport->action))(start_ccb);
}
diff --git a/sys/cam/scsi/scsi_pass.c b/sys/cam/scsi/scsi_pass.c
index 65a7aee..a3968f5 100644
--- a/sys/cam/scsi/scsi_pass.c
+++ b/sys/cam/scsi/scsi_pass.c
@@ -521,6 +521,7 @@ passioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *t
struct cam_periph *periph;
struct pass_softc *softc;
int error;
+ uint32_t priority;
periph = (struct cam_periph *)dev->si_drv1;
if (periph == NULL)
@@ -553,6 +554,11 @@ passioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *t
break;
}
+ /* Compatibility for RL/priority-unaware code. */
+ priority = inccb->ccb_h.pinfo.priority;
+ if (priority < CAM_RL_TO_PRIORITY(CAM_RL_NORMAL))
+ priority += CAM_RL_TO_PRIORITY(CAM_RL_NORMAL);
+
/*
* Non-immediate CCBs need a CCB from the per-device pool
* of CCBs, which is scheduled by the transport layer.
@@ -561,15 +567,14 @@ passioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *t
*/
if ((inccb->ccb_h.func_code & XPT_FC_QUEUED)
&& ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) {
- ccb = cam_periph_getccb(periph,
- inccb->ccb_h.pinfo.priority);
+ ccb = cam_periph_getccb(periph, priority);
ccb_malloced = 0;
} else {
ccb = xpt_alloc_ccb_nowait();
if (ccb != NULL)
xpt_setup_ccb(&ccb->ccb_h, periph->path,
- inccb->ccb_h.pinfo.priority);
+ priority);
ccb_malloced = 1;
}
OpenPOWER on IntegriCloud