|
@@ -996,18 +996,25 @@ __qdio_outbound_processing(struct qdio_q *q)
|
|
|
if (qdio_has_outbound_q_moved(q))
|
|
|
qdio_kick_outbound_handler(q);
|
|
|
|
|
|
- if (q->is_iqdio_q) {
|
|
|
+ if (q->queue_type == QDIO_ZFCP_QFMT) {
|
|
|
+ if ((!q->hydra_gives_outbound_pcis) &&
|
|
|
+ (!qdio_is_outbound_q_done(q)))
|
|
|
+ qdio_mark_q(q);
|
|
|
+ }
|
|
|
+ else if (((!q->is_iqdio_q) && (!q->is_pci_out)) ||
|
|
|
+ (q->queue_type == QDIO_IQDIO_QFMT_ASYNCH)) {
|
|
|
/*
|
|
|
- * for asynchronous queues, we better check, if the sent
|
|
|
- * buffer is already switched from PRIMED to EMPTY.
|
|
|
+ * make sure buffer switch from PRIMED to EMPTY is noticed
|
|
|
+ * and outbound_handler is called
|
|
|
*/
|
|
|
- if ((q->queue_type == QDIO_IQDIO_QFMT_ASYNCH) &&
|
|
|
- !qdio_is_outbound_q_done(q))
|
|
|
- qdio_mark_q(q);
|
|
|
-
|
|
|
- } else if (!q->hydra_gives_outbound_pcis)
|
|
|
- if (!qdio_is_outbound_q_done(q))
|
|
|
- qdio_mark_q(q);
|
|
|
+ if (qdio_is_outbound_q_done(q)) {
|
|
|
+ del_timer(&q->timer);
|
|
|
+ } else {
|
|
|
+ if (!timer_pending(&q->timer))
|
|
|
+ mod_timer(&q->timer, jiffies +
|
|
|
+ QDIO_FORCE_CHECK_TIMEOUT);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
qdio_release_q(q);
|
|
|
}
|
|
@@ -1826,6 +1833,7 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
|
|
|
q->queue_type = QDIO_IQDIO_QFMT_ASYNCH;
|
|
|
q->int_parm=int_parm;
|
|
|
q->is_input_q=0;
|
|
|
+ q->is_pci_out = 0;
|
|
|
q->schid = irq_ptr->schid;
|
|
|
q->cdev = cdev;
|
|
|
q->irq_ptr = irq_ptr;
|
|
@@ -1838,6 +1846,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
|
|
|
q->tasklet.data=(unsigned long)q;
|
|
|
q->tasklet.func=(void(*)(unsigned long))
|
|
|
&qdio_outbound_processing;
|
|
|
+ q->timer.function=(void(*)(unsigned long))
|
|
|
+ &qdio_outbound_processing;
|
|
|
+ q->timer.data = (long)q;
|
|
|
+ init_timer(&q->timer);
|
|
|
|
|
|
atomic_set(&q->busy_siga_counter,0);
|
|
|
q->timing.busy_start=0;
|
|
@@ -2635,6 +2647,7 @@ qdio_shutdown(struct ccw_device *cdev, int how)
|
|
|
|
|
|
for (i=0;i<irq_ptr->no_output_qs;i++) {
|
|
|
tasklet_kill(&irq_ptr->output_qs[i]->tasklet);
|
|
|
+ del_timer(&irq_ptr->output_qs[i]->timer);
|
|
|
wait_event_interruptible_timeout(cdev->private->wait_q,
|
|
|
!atomic_read(&irq_ptr->
|
|
|
output_qs[i]->
|
|
@@ -3458,6 +3471,10 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
|
|
|
qdio_perf_stat_inc(&perf_stats.outbound_cnt);
|
|
|
return;
|
|
|
}
|
|
|
+ if (callflags & QDIO_FLAG_PCI_OUT)
|
|
|
+ q->is_pci_out = 1;
|
|
|
+ else
|
|
|
+ q->is_pci_out = 0;
|
|
|
if (q->is_iqdio_q) {
|
|
|
/* one siga for every sbal */
|
|
|
while (count--)
|