@@ -36,10 +36,19 @@ debug_info_t *vfio_ccw_debug_trace_id;
3636 */
3737int vfio_ccw_sch_quiesce (struct subchannel * sch )
3838{
39- struct vfio_ccw_private * private = dev_get_drvdata (& sch -> dev );
39+ struct vfio_ccw_parent * parent = dev_get_drvdata (& sch -> dev );
40+ struct vfio_ccw_private * private = dev_get_drvdata (& parent -> dev );
4041 DECLARE_COMPLETION_ONSTACK (completion );
4142 int iretry , ret = 0 ;
4243
44+ /*
45+ * Probably an impossible situation, after being called through
46+ * FSM callbacks. But in the event it did, register a warning
47+ * and return as if things were fine.
48+ */
49+ if (WARN_ON (!private ))
50+ return 0 ;
51+
4352 iretry = 255 ;
4453 do {
4554
@@ -121,7 +130,23 @@ static void vfio_ccw_crw_todo(struct work_struct *work)
121130 */
122131static void vfio_ccw_sch_irq (struct subchannel * sch )
123132{
124- struct vfio_ccw_private * private = dev_get_drvdata (& sch -> dev );
133+ struct vfio_ccw_parent * parent = dev_get_drvdata (& sch -> dev );
134+ struct vfio_ccw_private * private = dev_get_drvdata (& parent -> dev );
135+
136+ /*
137+ * The subchannel should still be disabled at this point,
138+ * so an interrupt would be quite surprising. As with an
139+ * interrupt while the FSM is closed, let's attempt to
140+ * disable the subchannel again.
141+ */
142+ if (!private ) {
143+ VFIO_CCW_MSG_EVENT (2 , "sch %x.%x.%04x: unexpected interrupt\n" ,
144+ sch -> schid .cssid , sch -> schid .ssid ,
145+ sch -> schid .sch_no );
146+
147+ cio_disable_subchannel (sch );
148+ return ;
149+ }
125150
126151 inc_irq_stat (IRQIO_CIO );
127152 vfio_ccw_fsm_event (private , VFIO_CCW_EVENT_INTERRUPT );
@@ -201,10 +226,19 @@ static void vfio_ccw_free_private(struct vfio_ccw_private *private)
201226 mutex_destroy (& private -> io_mutex );
202227 kfree (private );
203228}
229+
230+ static void vfio_ccw_free_parent (struct device * dev )
231+ {
232+ struct vfio_ccw_parent * parent = container_of (dev , struct vfio_ccw_parent , dev );
233+
234+ kfree (parent );
235+ }
236+
204237static int vfio_ccw_sch_probe (struct subchannel * sch )
205238{
206239 struct pmcw * pmcw = & sch -> schib .pmcw ;
207240 struct vfio_ccw_private * private ;
241+ struct vfio_ccw_parent * parent ;
208242 int ret = - ENOMEM ;
209243
210244 if (pmcw -> qf ) {
@@ -213,38 +247,58 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
213247 return - ENODEV ;
214248 }
215249
250+ parent = kzalloc (sizeof (* parent ), GFP_KERNEL );
251+ if (!parent )
252+ return - ENOMEM ;
253+
254+ dev_set_name (& parent -> dev , "parent" );
255+ parent -> dev .parent = & sch -> dev ;
256+ parent -> dev .release = & vfio_ccw_free_parent ;
257+ ret = device_register (& parent -> dev );
258+ if (ret )
259+ goto out_free ;
260+
216261 private = vfio_ccw_alloc_private (sch );
217- if (IS_ERR (private ))
262+ if (IS_ERR (private )) {
263+ device_unregister (& parent -> dev );
218264 return PTR_ERR (private );
265+ }
219266
220- dev_set_drvdata (& sch -> dev , private );
267+ dev_set_drvdata (& sch -> dev , parent );
268+ dev_set_drvdata (& parent -> dev , private );
221269
222- private -> mdev_type .sysfs_name = "io" ;
223- private -> mdev_type .pretty_name = "I/O subchannel (Non-QDIO)" ;
224- private -> mdev_types [0 ] = & private -> mdev_type ;
225- ret = mdev_register_parent (& private -> parent , & sch -> dev ,
270+ parent -> mdev_type .sysfs_name = "io" ;
271+ parent -> mdev_type .pretty_name = "I/O subchannel (Non-QDIO)" ;
272+ parent -> mdev_types [0 ] = & parent -> mdev_type ;
273+ ret = mdev_register_parent (& parent -> parent , & sch -> dev ,
226274 & vfio_ccw_mdev_driver ,
227- private -> mdev_types , 1 );
275+ parent -> mdev_types , 1 );
228276 if (ret )
229- goto out_free ;
277+ goto out_unreg ;
230278
231279 VFIO_CCW_MSG_EVENT (4 , "bound to subchannel %x.%x.%04x\n" ,
232280 sch -> schid .cssid , sch -> schid .ssid ,
233281 sch -> schid .sch_no );
234282 return 0 ;
235283
284+ out_unreg :
285+ device_unregister (& parent -> dev );
236286out_free :
287+ dev_set_drvdata (& parent -> dev , NULL );
237288 dev_set_drvdata (& sch -> dev , NULL );
238- vfio_ccw_free_private (private );
289+ if (private )
290+ vfio_ccw_free_private (private );
239291 return ret ;
240292}
241293
242294static void vfio_ccw_sch_remove (struct subchannel * sch )
243295{
244- struct vfio_ccw_private * private = dev_get_drvdata (& sch -> dev );
296+ struct vfio_ccw_parent * parent = dev_get_drvdata (& sch -> dev );
297+ struct vfio_ccw_private * private = dev_get_drvdata (& parent -> dev );
245298
246- mdev_unregister_parent (& private -> parent );
299+ mdev_unregister_parent (& parent -> parent );
247300
301+ device_unregister (& parent -> dev );
248302 dev_set_drvdata (& sch -> dev , NULL );
249303
250304 vfio_ccw_free_private (private );
@@ -256,7 +310,11 @@ static void vfio_ccw_sch_remove(struct subchannel *sch)
256310
257311static void vfio_ccw_sch_shutdown (struct subchannel * sch )
258312{
259- struct vfio_ccw_private * private = dev_get_drvdata (& sch -> dev );
313+ struct vfio_ccw_parent * parent = dev_get_drvdata (& sch -> dev );
314+ struct vfio_ccw_private * private = dev_get_drvdata (& parent -> dev );
315+
316+ if (WARN_ON (!private ))
317+ return ;
260318
261319 vfio_ccw_fsm_event (private , VFIO_CCW_EVENT_CLOSE );
262320 vfio_ccw_fsm_event (private , VFIO_CCW_EVENT_NOT_OPER );
@@ -274,7 +332,8 @@ static void vfio_ccw_sch_shutdown(struct subchannel *sch)
274332 */
275333static int vfio_ccw_sch_event (struct subchannel * sch , int process )
276334{
277- struct vfio_ccw_private * private = dev_get_drvdata (& sch -> dev );
335+ struct vfio_ccw_parent * parent = dev_get_drvdata (& sch -> dev );
336+ struct vfio_ccw_private * private = dev_get_drvdata (& parent -> dev );
278337 unsigned long flags ;
279338 int rc = - EAGAIN ;
280339
@@ -287,8 +346,10 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process)
287346
288347 rc = 0 ;
289348
290- if (cio_update_schib (sch ))
291- vfio_ccw_fsm_event (private , VFIO_CCW_EVENT_NOT_OPER );
349+ if (cio_update_schib (sch )) {
350+ if (private )
351+ vfio_ccw_fsm_event (private , VFIO_CCW_EVENT_NOT_OPER );
352+ }
292353
293354out_unlock :
294355 spin_unlock_irqrestore (sch -> lock , flags );
@@ -326,7 +387,8 @@ static void vfio_ccw_queue_crw(struct vfio_ccw_private *private,
326387static int vfio_ccw_chp_event (struct subchannel * sch ,
327388 struct chp_link * link , int event )
328389{
329- struct vfio_ccw_private * private = dev_get_drvdata (& sch -> dev );
390+ struct vfio_ccw_parent * parent = dev_get_drvdata (& sch -> dev );
391+ struct vfio_ccw_private * private = dev_get_drvdata (& parent -> dev );
330392 int mask = chp_ssd_get_mask (& sch -> ssd_info , link );
331393 int retry = 255 ;
332394
0 commit comments