/* * Handle charLpEvents and route to the appropriate routine */ static void vioHandleCharEvent(struct HvLpEvent *event) { int charminor; if (event == NULL) return; charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; switch (charminor) { case viocharopen: vioHandleOpenEvent(event); break; case viocharclose: vioHandleCloseEvent(event); break; case viochardata: vioHandleData(event); break; case viocharack: vioHandleAck(event); break; case viocharconfig: vioHandleConfig(event); break; default: if ((event->xFlags.xFunction == HvLpEvent_Function_Int) && (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)) { event->xRc = HvLpEvent_Rc_InvalidSubtype; HvCallEvent_ackLpEvent(event); } } }
static void __init handle_block_event(struct HvLpEvent *event) { struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; struct vio_waitevent *pwe; if (event == NULL) /* Notification that a partition went away! */ return; /* First, we should NEVER get an int here...only acks */ if (hvlpevent_is_int(event)) { printk(KERN_WARNING "handle_viod_request: " "Yikes! got an int in viodasd event handler!\n"); if (hvlpevent_need_ack(event)) { event->xRc = HvLpEvent_Rc_InvalidSubtype; HvCallEvent_ackLpEvent(event); } return; } switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { case vioblockopen: /* * Handle a response to an open request. We get all the * disk information in the response, so update it. The * correlation token contains a pointer to a waitevent * structure that has a completion in it. update the * return code in the waitevent structure and post the * completion to wake up the guy who sent the request */ pwe = (struct vio_waitevent *)event->xCorrelationToken; pwe->rc = event->xRc; pwe->sub_result = bevent->sub_result; complete(&pwe->com); break; case vioblockclose: break; default: printk(KERN_WARNING "handle_viod_request: unexpected subtype!"); if (hvlpevent_need_ack(event)) { event->xRc = HvLpEvent_Rc_InvalidSubtype; HvCallEvent_ackLpEvent(event); } } }
static void __init handle_cd_event(struct HvLpEvent *event) { struct viocdlpevent *bevent; struct vio_waitevent *pwe; if (!event) /* Notification that a partition went away! */ return; /* First, we should NEVER get an int here...only acks */ if (hvlpevent_is_int(event)) { printk(KERN_WARNING "handle_cd_event: got an unexpected int\n"); if (hvlpevent_need_ack(event)) { event->xRc = HvLpEvent_Rc_InvalidSubtype; HvCallEvent_ackLpEvent(event); } return; } bevent = (struct viocdlpevent *)event; switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { case viocdgetinfo: pwe = (struct vio_waitevent *)event->xCorrelationToken; pwe->rc = event->xRc; pwe->sub_result = bevent->sub_result; complete(&pwe->com); break; default: printk(KERN_WARNING "handle_cd_event: " "message with unexpected subtype %0x04X!\n", event->xSubtype & VIOMINOR_SUBTYPE_MASK); if (hvlpevent_need_ack(event)) { event->xRc = HvLpEvent_Rc_InvalidSubtype; HvCallEvent_ackLpEvent(event); } } }
/* * Handle an open charLpEvent. Could be either interrupt or ack */ static void vioHandleOpenEvent(struct HvLpEvent *event) { unsigned long flags; struct viocharlpevent *cevent = (struct viocharlpevent *)event; u8 port = cevent->virtual_device; struct port_info *pi; int reject = 0; if (event->xFlags.xFunction == HvLpEvent_Function_Ack) { if (port >= VTTY_PORTS) return; spin_lock_irqsave(&consolelock, flags); /* Got the lock, don't cause console output */ pi = &port_info[port]; if (event->xRc == HvLpEvent_Rc_Good) { pi->seq = pi->ack = 0; /* * This line allows connections from the primary * partition but once one is connected from the * primary partition nothing short of a reboot * of linux will allow access from the hosting * partition again without a required iSeries fix. */ pi->lp = event->xTargetLp; } spin_unlock_irqrestore(&consolelock, flags); if (event->xRc != HvLpEvent_Rc_Good) printk(VIOCONS_KERN_WARN "handle_open_event: event->xRc == (%d).\n", event->xRc); if (event->xCorrelationToken != 0) { atomic_t *aptr= (atomic_t *)event->xCorrelationToken; atomic_set(aptr, 1); } else printk(VIOCONS_KERN_WARN "wierd...got open ack without atomic\n"); return; } /* This had better require an ack, otherwise complain */ if (event->xFlags.xAckInd != HvLpEvent_AckInd_DoAck) { printk(VIOCONS_KERN_WARN "viocharopen without ack bit!\n"); return; } spin_lock_irqsave(&consolelock, flags); /* Got the lock, don't cause console output */ /* Make sure this is a good virtual tty */ if (port >= VTTY_PORTS) { event->xRc = HvLpEvent_Rc_SubtypeError; cevent->subtype_result_code = viorc_openRejected; /* * Flag state here since we can't printk while holding * a spinlock. */ reject = 1; } else { pi = &port_info[port]; if ((pi->lp != HvLpIndexInvalid) && (pi->lp != event->xSourceLp)) { /* * If this is tty is already connected to a different * partition, fail. */ event->xRc = HvLpEvent_Rc_SubtypeError; cevent->subtype_result_code = viorc_openRejected; reject = 2; } else { pi->lp = event->xSourceLp; event->xRc = HvLpEvent_Rc_Good; cevent->subtype_result_code = viorc_good; pi->seq = pi->ack = 0; reject = 0; } } spin_unlock_irqrestore(&consolelock, flags); if (reject == 1) printk(VIOCONS_KERN_WARN "open rejected: bad virtual tty.\n"); else if (reject == 2) printk(VIOCONS_KERN_WARN "open rejected: console in exclusive use by another partition.\n"); /* Return the acknowledgement */ HvCallEvent_ackLpEvent(event); }