[MTHCA/IBBUS] add HIBERNATE and STANDBY support (for mthca/bus/ipoib)
authorsleybo <sleybo@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Wed, 7 Feb 2007 14:29:16 +0000 (14:29 +0000)
committersleybo <sleybo@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Wed, 7 Feb 2007 14:29:16 +0000 (14:29 +0000)
git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@591 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

core/al/kernel/al_pnp.c
core/bus/kernel/bus_driver.h
core/bus/kernel/bus_iou_mgr.c
core/bus/kernel/bus_pnp.c
core/bus/kernel/bus_port_mgr.c
core/complib/kernel/cl_pnp_po.c
hw/mthca/kernel/hca_driver.h
hw/mthca/kernel/hca_pnp.c
hw/mthca/kernel/mthca_cmd.c

index 5dd72c7..df7dffa 100644 (file)
@@ -479,6 +479,10 @@ __pnp_notify_user(
        CL_ASSERT( p_context );\r
        CL_ASSERT( p_event_rec );\r
 \r
+       AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_PNP,\r
+               ("p_event_rec->pnp_event = 0x%x (%s)\n",\r
+               p_event_rec->pnp_event, ib_get_pnp_event_str( p_event_rec->pnp_event )) );\r
+\r
        /* Setup the PnP record for the callback. */\r
        cl_memclr( &u, sizeof(u) );\r
        u.user_rec.h_pnp = p_reg;\r
index eb3c3ac..98c00be 100644 (file)
@@ -172,6 +172,12 @@ typedef struct _bus_pdo_ext
         */\r
        boolean_t                               b_reported_missing;\r
 \r
+       /* Flag to control the behaviour of the driver during hibernation */\r
+       uint32_t                                        b_hibernating;\r
+\r
+       /* work item for handling Power Management request */\r
+       PIO_WORKITEM                    p_po_work_item;\r
+       \r
 }      bus_pdo_ext_t;\r
 \r
 \r
index b3dea68..6e21b90 100644 (file)
@@ -391,6 +391,8 @@ free_iou_mgr(
                {\r
                        CL_ASSERT( !p_ext->b_present );\r
                        p_ext->b_reported_missing = TRUE;\r
+                       BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n",\r
+                               p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->b_present, p_ext->b_reported_missing ) );\r
                        continue;\r
                }\r
                if( p_ext->h_ca )\r
@@ -492,6 +494,80 @@ iou_mgr_get_bus_relations(
 }\r
 \r
 \r
+static ib_api_status_t\r
+__iou_was_hibernated(\r
+       IN                              ib_pnp_iou_rec_t*                       p_pnp_rec )\r
+{\r
+       NTSTATUS                status;\r
+       cl_list_item_t          *p_list_item;\r
+       bus_iou_ext_t           *p_iou_ext;\r
+       bus_pdo_ext_t   *p_pdo_ext = NULL;\r
+       size_t                  n_devs = 0;\r
+       cl_qlist_t*             p_pdo_list = &gp_iou_mgr->iou_list;\r
+\r
+       BUS_ENTER( BUS_DBG_PNP );\r
+       \r
+       cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
+       \r
+       /* Count the number of child devices. */\r
+       for( p_list_item = cl_qlist_head( p_pdo_list );\r
+               p_list_item != cl_qlist_end( p_pdo_list );\r
+               p_list_item = cl_qlist_next( p_list_item ) )\r
+       {\r
+               p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
+               p_iou_ext = (bus_iou_ext_t*)p_pdo_ext;\r
+\r
+               /* TODO: maybe we need more search patterns like vend_id, dev_id ... */\r
+               if( p_pdo_ext->b_present && p_pdo_ext->b_hibernating &&\r
+                       (p_iou_ext->guid == p_pnp_rec->pnp_rec.guid) )\r
+               {\r
+                       n_devs++;\r
+                       break;\r
+               }\r
+\r
+               BUS_TRACE( BUS_DBG_PNP, \r
+                       ("Skipped PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
+                       p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
+                       p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
+                       p_pdo_ext->b_hibernating, p_iou_ext->guid ) );\r
+       }\r
+\r
+       if (n_devs)\r
+       {\r
+               /* Take a reference on the parent HCA. */\r
+               p_pdo_ext->h_ca = acquire_ca( p_pnp_rec->ca_guid );\r
+               if( !p_pdo_ext->h_ca )\r
+               {\r
+                       BUS_TRACE( BUS_DBG_ERROR, ("acquire_ca failed to find CA by guid %I64x\n",\r
+                               p_pnp_rec->ca_guid ) );\r
+                       status = IB_INVALID_GUID;\r
+               }\r
+               else \r
+               {\r
+                       p_pdo_ext->b_hibernating = FALSE;\r
+                       p_pnp_rec->pnp_rec.context = p_pdo_ext;\r
+                       status = IB_SUCCESS;\r
+                       p_iou_ext = (bus_iou_ext_t*)p_pdo_ext;\r
+                       BUS_TRACE( BUS_DBG_PNP, \r
+                               ("Found PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
+                               p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
+                               p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
+                               p_pdo_ext->b_hibernating, p_iou_ext->guid ) );\r
+               }\r
+       }\r
+       else \r
+       {\r
+               BUS_TRACE( BUS_DBG_PNP, ("Failed to find PDO for guid  %I64x .\n",\r
+                       p_pnp_rec->pnp_rec.guid ) );\r
+               status = IB_NOT_FOUND;\r
+       }\r
+\r
+       cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
+\r
+       BUS_EXIT( BUS_DBG_PNP );\r
+       return status;\r
+}\r
+\r
 ib_api_status_t\r
 iou_mgr_iou_add(\r
        IN                              ib_pnp_iou_rec_t*                       p_pnp_rec )\r
@@ -502,6 +578,16 @@ iou_mgr_iou_add(
 \r
        BUS_ENTER( BUS_DBG_PNP );\r
 \r
+       /* Upon hibernating of the computer IB_BUS driver doesn't remove PDO, but\r
+          marks with a flag. So we first try to find an existing PDO for this port,\r
+          marked with this flag. If it was found, we turn off the flag and use this PDO */\r
+       status = __iou_was_hibernated(p_pnp_rec);\r
+       if( status != IB_NOT_FOUND )\r
+       {\r
+               BUS_EXIT( BUS_DBG_PNP );\r
+               return status;\r
+       }\r
+\r
        /* Create the PDO for the new port device. */\r
        status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_iou_ext_t),\r
                NULL, FILE_DEVICE_CONTROLLER, \r
@@ -526,6 +612,8 @@ iou_mgr_iou_add(
        p_iou_ext->pdo.p_parent_ext = bus_globals.p_bus_ext;\r
        p_iou_ext->pdo.b_present = TRUE;\r
        p_iou_ext->pdo.b_reported_missing = FALSE;\r
+       BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n",\r
+               p_iou_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_iou_ext, p_iou_ext->pdo.b_present, p_iou_ext->pdo.b_reported_missing ) );\r
 \r
        p_iou_ext->guid = p_pnp_rec->pnp_rec.guid;\r
        p_iou_ext->vend_id = cl_ntoh32( p_pnp_rec->vend_id );\r
@@ -594,7 +682,19 @@ iou_mgr_iou_remove(
         * to proceed should it occur before the port's PDO is cleaned up.\r
         */\r
        cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
+       CL_ASSERT( p_ext->h_ca );\r
+\r
+       if( p_ext->b_hibernating )\r
+       {\r
+               BUS_TRACE( BUS_DBG_PNP, ("Skip port removing for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d .\n",\r
+                       p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, \r
+                       p_ext->b_reported_missing, p_ext->b_hibernating ) );\r
+               goto hca_deref;\r
+       }\r
+\r
        p_ext->b_present = FALSE;\r
+       BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n",\r
+               p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->b_present, p_ext->b_reported_missing ) );\r
 \r
        /* Invalidate removal relations for the bus driver. */\r
        IoInvalidateDeviceRelations( bus_globals.p_bus_ext->cl_ext.p_pdo,\r
@@ -604,6 +704,7 @@ iou_mgr_iou_remove(
        IoInvalidateDeviceRelations(\r
                p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
 \r
+hca_deref:\r
        deref_al_obj( &p_ext->h_ca->obj );\r
        p_ext->h_ca = NULL;\r
        cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
@@ -758,6 +859,8 @@ iou_surprise_remove(
        p_ext = p_dev_obj->DeviceExtension;\r
        p_ext->pdo.b_present = FALSE;\r
        p_ext->pdo.b_reported_missing = TRUE;\r
+       BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n",\r
+               p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) );\r
 \r
        *p_action = IrpComplete;\r
 \r
@@ -1280,6 +1383,47 @@ iou_query_interface(
 }\r
 \r
 \r
+\r
+/* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
+static void\r
+__HibernateUpWorkItem(\r
+       IN                              DEVICE_OBJECT*                          p_dev_obj,\r
+       IN                              void*                                           context )\r
+{\r
+       IO_STACK_LOCATION       *p_io_stack;\r
+       bus_pdo_ext_t           *p_ext;\r
+       IRP                                     *p_irp;\r
+       POWER_STATE powerState;\r
+\r
+       BUS_ENTER( BUS_DBG_POWER );\r
+\r
+       p_ext = (bus_pdo_ext_t*)p_dev_obj->DeviceExtension;\r
+       p_irp = (IRP*)context;\r
+       p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+       IoFreeWorkItem( p_ext->p_po_work_item );\r
+       p_ext->p_po_work_item = NULL;\r
+\r
+       while (!p_ext->h_ca) {\r
+               BUS_TRACE( BUS_DBG_PNP, ("Waiting for the end of HCA registration ... \n"));\r
+               cl_thread_suspend( 200 );       /* suspend for 200 ms */\r
+       }\r
+\r
+       p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
+       powerState = PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
+\r
+       BUS_TRACE( BUS_DBG_POWER, \r
+               ("PoSetPowerState: old state %d, new state to %d\n", \r
+               powerState.DeviceState, p_ext->dev_po_state ));\r
+\r
+       p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+       PoStartNextPowerIrp( p_irp );\r
+       IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+       IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+\r
+       BUS_EXIT( BUS_DBG_POWER );\r
+}\r
+\r
 /*\r
  * The PDOs created by the IB Bus driver are software devices.  As such,\r
  * all power states are supported.  It is left to the HCA power policy \r
@@ -1291,6 +1435,7 @@ iou_set_power(
        IN                              IRP* const                                      p_irp,\r
                OUT                     cl_irp_action_t* const          p_action )\r
 {\r
+       NTSTATUS                        status = STATUS_SUCCESS;\r
        IO_STACK_LOCATION       *p_io_stack;\r
        bus_pdo_ext_t           *p_ext;\r
 \r
@@ -1299,8 +1444,42 @@ iou_set_power(
        p_ext = p_dev_obj->DeviceExtension;\r
        p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
 \r
+       BUS_TRACE( BUS_DBG_POWER, \r
+               ("SET_POWER for PDO %p (ext %p): type %s, state %d, action %d \n",\r
+               p_dev_obj, p_ext,\r
+               (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
+               p_io_stack->Parameters.Power.State.DeviceState, \r
+               p_io_stack->Parameters.Power.ShutdownType ));\r
+\r
+       if ((p_io_stack->Parameters.Power.Type == SystemPowerState) &&\r
+               (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate ||\r
+               p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 ))\r
+       {\r
+               BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj));\r
+               p_ext->b_hibernating = TRUE;\r
+       }\r
+\r
        if( p_io_stack->Parameters.Power.Type == DevicePowerState )\r
        {\r
+               /* after hibernation PDO is not ready for work. we need to wait for finishing of the HCA registration */\r
+               if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && p_ext->b_hibernating)\r
+               {\r
+                       /* Process in a work item - deregister_ca and HcaDeinit block. */\r
+                       ASSERT( !p_ext->p_po_work_item );\r
+                       p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj );\r
+                       if( !p_ext->p_po_work_item )\r
+                               status = STATUS_INSUFFICIENT_RESOURCES;\r
+                       else {\r
+                               /* Process in work item callback. */\r
+                               IoMarkIrpPending( p_irp );\r
+                               IoQueueWorkItem(\r
+                                       p_ext->p_po_work_item, __HibernateUpWorkItem, DelayedWorkQueue, p_irp );\r
+                               *p_action = IrpDoNothing;\r
+                               BUS_EXIT( BUS_DBG_POWER );\r
+                               return STATUS_PENDING;\r
+                       }\r
+               }\r
+\r
                /* Notify the power manager. */\r
                p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
                PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
index 089f77c..00190ff 100644 (file)
@@ -827,12 +827,13 @@ __fdo_query_power(
                /* Fail any requests to hibernate or sleep the system. */\r
                switch( p_io_stack->Parameters.Power.State.SystemState )\r
                {\r
+                       case PowerSystemHibernate:\r
+                       case PowerSystemSleeping1:      // STANDBY support\r
                        case PowerSystemWorking:\r
                        case PowerSystemShutdown:\r
-                               /* We only support fully working and shutdown system states. */\r
-                               break;\r
+                               break;\r
 \r
-                       default:\r
+                       default:\r
                                status = STATUS_NOT_SUPPORTED;\r
                }\r
                break;\r
@@ -931,7 +932,7 @@ __set_power_completion(
        status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
                __request_power_completion, p_irp, NULL );\r
 \r
-       if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
+       if( status != STATUS_PENDING )\r
        {\r
                PoStartNextPowerIrp( p_irp );\r
                /* Propagate the failure. */\r
@@ -962,6 +963,13 @@ __fdo_set_power(
        p_ext = p_dev_obj->DeviceExtension;\r
        p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
 \r
+       BUS_TRACE( BUS_DBG_POWER, \r
+               ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d \n",\r
+               p_dev_obj, p_ext,\r
+               (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
+               p_io_stack->Parameters.Power.State.DeviceState, \r
+               p_io_stack->Parameters.Power.ShutdownType ));\r
+\r
        switch( p_io_stack->Parameters.Power.Type )\r
        {\r
        case SystemPowerState:\r
@@ -1034,6 +1042,8 @@ bus_get_relations(
                return STATUS_NO_SUCH_DEVICE;\r
        }\r
 \r
+       BUS_TRACE( BUS_DBG_PNP, ("Found %d PDOs .\n", n_devs ));\r
+\r
        /* Add space for our child IOUs. */\r
        status = cl_alloc_relations( p_irp, n_devs );\r
        if( !NT_SUCCESS( status ) )\r
@@ -1058,12 +1068,18 @@ bus_get_relations(
                         * the PDO will get cleaned up.\r
                         */\r
                        p_pdo_ext->b_reported_missing = TRUE;\r
+                       BUS_TRACE( BUS_DBG_PNP, ("Don't report PDO! %s: PDO %p, ext %p, present %d, missing %d .\n",\r
+                               p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
+                               p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing ) );\r
                        continue;\r
                }\r
 \r
                if( ca_guid && p_pdo_ext->ca_guid != ca_guid )\r
                        continue;\r
 \r
+               BUS_TRACE( BUS_DBG_PNP, ("Reported PDO %p(=%p), ext %p.\n", \r
+                       p_pdo_ext->cl_ext.p_self_do, p_pdo_ext->cl_ext.p_pdo, p_pdo_ext ));\r
+               \r
                p_rel->Objects[p_rel->Count] = p_pdo_ext->cl_ext.p_pdo;\r
                ObReferenceObject( p_rel->Objects[p_rel->Count++] );\r
        }\r
index b702479..60b4f7b 100644 (file)
@@ -385,6 +385,8 @@ free_port_mgr(
                {\r
                        CL_ASSERT( !p_ext->b_present );\r
                        p_ext->b_reported_missing = TRUE;\r
+                       BUS_TRACE( BUS_DBG_PNP, ("%s: PDO %p, ext %p, present %d, missing %d .\n",\r
+                               p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, p_ext->b_reported_missing ) );\r
                        continue;\r
                }\r
                if( p_ext->h_ca )\r
@@ -396,6 +398,8 @@ free_port_mgr(
                        /* Release the reference on the CA object. */\r
                        deref_al_obj( &p_ext->h_ca->obj );\r
                }\r
+               BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s: PDO %p, ext %p\n",\r
+                       p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext ) );\r
                IoDeleteDevice( p_ext->cl_ext.p_self_do );\r
        }\r
 \r
@@ -485,6 +489,78 @@ port_mgr_get_bus_relations(
        return STATUS_SUCCESS;\r
 }\r
 \r
+static ib_api_status_t\r
+__port_was_hibernated(\r
+       IN                              ib_pnp_port_rec_t*                      p_pnp_rec )\r
+{\r
+       NTSTATUS                status;\r
+       cl_list_item_t          *p_list_item;\r
+       bus_port_ext_t  *p_port_ext;\r
+       bus_pdo_ext_t   *p_pdo_ext = NULL;\r
+       size_t                  n_devs = 0;\r
+       cl_qlist_t*             p_pdo_list = &gp_port_mgr->port_list;\r
+\r
+       BUS_ENTER( BUS_DBG_PNP );\r
+       \r
+       cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
+       \r
+       /* Count the number of child devices. */\r
+       for( p_list_item = cl_qlist_head( p_pdo_list );\r
+               p_list_item != cl_qlist_end( p_pdo_list );\r
+               p_list_item = cl_qlist_next( p_list_item ) )\r
+       {\r
+               p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
+               p_port_ext = (bus_port_ext_t*)p_pdo_ext;\r
+       \r
+               if( p_pdo_ext->b_present && p_pdo_ext->b_hibernating &&\r
+                       (p_port_ext->port_guid == p_pnp_rec->p_port_attr->port_guid) )\r
+               {\r
+                       n_devs++;\r
+                       break;\r
+               }\r
+\r
+               BUS_TRACE( BUS_DBG_PNP, \r
+                       ("Skipped PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
+                       p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
+                       p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
+                       p_pdo_ext->b_hibernating, p_port_ext->port_guid ) );\r
+       }\r
+\r
+       if (n_devs)\r
+       {\r
+               /* Take a reference on the parent HCA. */\r
+               p_pdo_ext->h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid );\r
+               if( !p_pdo_ext->h_ca )\r
+               {\r
+                       BUS_TRACE( BUS_DBG_ERROR, ("acquire_ca failed to find CA by guid %I64x\n",\r
+                               p_pnp_rec->p_ca_attr->ca_guid ) );\r
+                       status = IB_INVALID_GUID;\r
+               }\r
+               else \r
+               {\r
+                       p_pdo_ext->b_hibernating = FALSE;\r
+                       p_pnp_rec->pnp_rec.context = p_pdo_ext;\r
+                       status = IB_SUCCESS;\r
+                       p_port_ext = (bus_port_ext_t*)p_pdo_ext;\r
+                       BUS_TRACE( BUS_DBG_PNP, \r
+                               ("Found PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
+                               p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
+                               p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
+                               p_pdo_ext->b_hibernating, p_port_ext->port_guid ) );\r
+               }\r
+       }\r
+       else \r
+       {\r
+               BUS_TRACE( BUS_DBG_PNP, ("Failed to find PDO for guid  %I64x .\n",\r
+                       p_pnp_rec->p_ca_attr->ca_guid ) );\r
+               status = IB_NOT_FOUND;\r
+       }\r
+\r
+       cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
+\r
+       BUS_EXIT( BUS_DBG_PNP );\r
+       return status;\r
+}\r
 \r
 ib_api_status_t\r
 port_mgr_port_add(\r
@@ -502,6 +578,16 @@ port_mgr_port_add(
                return IB_NOT_DONE;\r
        }\r
 \r
+       /* Upon hibernating of the computer IB_BUS driver doesn't remove PDO, but\r
+          marks with a flag. So we first try to find an existing PDO for this port,\r
+          marked with this flag. If it was found, we turn off the flag and use this PDO */\r
+       status = __port_was_hibernated(p_pnp_rec);\r
+       if( status != IB_NOT_FOUND )\r
+       {\r
+               BUS_EXIT( BUS_DBG_PNP );\r
+               return status;\r
+       }\r
+\r
        /* Create the PDO for the new port device. */\r
        status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_port_ext_t),\r
                NULL, FILE_DEVICE_CONTROLLER,\r
@@ -526,6 +612,11 @@ port_mgr_port_add(
        p_port_ext->pdo.p_parent_ext = bus_globals.p_bus_ext;\r
        p_port_ext->pdo.b_present = TRUE;\r
        p_port_ext->pdo.b_reported_missing = FALSE;\r
+       p_port_ext->pdo.b_hibernating = FALSE;\r
+       p_port_ext->pdo.p_po_work_item = NULL;\r
+       BUS_TRACE( BUS_DBG_PNP, ("Created device for %s: PDO %p,ext %p, present %d, missing %d .\n",\r
+               p_port_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_pdo, p_port_ext, p_port_ext->pdo.b_present, \r
+               p_port_ext->pdo.b_reported_missing ) );\r
 \r
        /* Cache the CA GUID. */\r
        p_port_ext->pdo.ca_guid = p_pnp_rec->p_ca_attr->ca_guid;\r
@@ -534,6 +625,7 @@ port_mgr_port_add(
        p_port_ext->pdo.h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid );\r
        if( !p_port_ext->pdo.h_ca )\r
        {\r
+               BUS_TRACE( BUS_DBG_PNP, ("Deleted device: PDO %p\n", p_pdo ));\r
                IoDeleteDevice( p_pdo );\r
                BUS_TRACE_EXIT( BUS_DBG_ERROR, ("acquire_ca failed to find CA.\n") );\r
                return IB_INVALID_GUID;\r
@@ -586,7 +678,18 @@ port_mgr_port_remove(
         */\r
        cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
        CL_ASSERT( p_ext->h_ca );\r
+\r
+       if( p_ext->b_hibernating )\r
+       {\r
+               BUS_TRACE( BUS_DBG_PNP, ("Skip port removing for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d .\n",\r
+                       p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, \r
+                       p_ext->b_reported_missing, p_ext->b_hibernating ) );\r
+               goto hca_deref;\r
+       }\r
+\r
        p_ext->b_present = FALSE;\r
+       BUS_TRACE( BUS_DBG_PNP, ("Mark removing %s: PDO %p, ext %p, present %d, missing %d .\n",\r
+               p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, p_ext->b_reported_missing ) );\r
 \r
        /* Invalidate removal relations for the bus driver. */\r
        IoInvalidateDeviceRelations( bus_globals.p_bus_ext->cl_ext.p_pdo,\r
@@ -596,6 +699,7 @@ port_mgr_port_remove(
        IoInvalidateDeviceRelations(\r
                p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
 \r
+hca_deref:\r
        deref_al_obj( &p_ext->h_ca->obj );\r
        p_ext->h_ca = NULL;\r
        cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
@@ -620,7 +724,6 @@ port_start(
 \r
        /* Notify the Power Manager that the device is started. */\r
        PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
-\r
        *p_action = IrpComplete;\r
        BUS_EXIT( BUS_DBG_PNP );\r
        return STATUS_SUCCESS;\r
@@ -674,7 +777,7 @@ port_release_resources(
 \r
        /* Remove this PDO from its list. */\r
        cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
-       BUS_TRACE( BUS_DBG_PNP, ("Removing port from vector.\n") );\r
+       BUS_TRACE( BUS_DBG_PNP, ("Removing port from vector: PDO %p, ext %p\n", p_dev_obj, p_ext) );\r
        cl_qlist_remove_item( &gp_port_mgr->port_list, &p_ext->pdo.list_item );\r
        cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
        po_state.DeviceState = PowerDeviceD3;\r
@@ -704,7 +807,7 @@ port_remove(
                cl_set_pnp_state( &p_ext->pdo.cl_ext, NotStarted );\r
                /* Don't delete the device.  It may simply be disabled. */\r
                *p_action = IrpComplete;\r
-               BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device still present.\n") );\r
+               BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device still present: PDO %p, ext %p\n", p_dev_obj, p_ext) );\r
                return STATUS_SUCCESS;\r
        }\r
 \r
@@ -713,7 +816,7 @@ port_remove(
                /* Reset the state to RemovePending.  Complib set it to Deleted. */\r
                cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
                *p_action = IrpComplete;\r
-               BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device not reported missing yet.\n") );\r
+               BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device not reported missing yet: PDO %p, ext %p\n", p_dev_obj, p_ext) );\r
                return STATUS_SUCCESS;\r
        }\r
 \r
@@ -727,6 +830,8 @@ port_remove(
        p_irp->IoStatus.Status = STATUS_SUCCESS;\r
        IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
 \r
+       BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s: PDO %p(=%p), ext %p\n",\r
+               p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, p_dev_obj, p_ext ) );\r
        IoDeleteDevice( p_dev_obj );\r
 \r
        *p_action = IrpDoNothing;\r
@@ -750,6 +855,9 @@ port_surprise_remove(
        p_ext = p_dev_obj->DeviceExtension;\r
        p_ext->pdo.b_present = FALSE;\r
        p_ext->pdo.b_reported_missing = TRUE;\r
+       BUS_TRACE( BUS_DBG_PNP, ("%s: PDO %p, ext %p, present %d, missing %d .\n",\r
+               p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, \r
+               p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) );\r
 \r
        *p_action = IrpComplete;\r
 \r
@@ -1122,6 +1230,7 @@ port_query_ipoib_ifc(
        ipoib_ifc_data_t                *p_ipoib_data;\r
        bus_port_ext_t                  *p_ext;\r
        const GUID                              *p_guid;\r
+       \r
 \r
        BUS_ENTER( BUS_DBG_PNP );\r
 \r
@@ -1129,6 +1238,10 @@ port_query_ipoib_ifc(
 \r
        p_ext = p_dev_obj->DeviceExtension;\r
 \r
+       BUS_TRACE( BUS_DBG_PNP, ("Query i/f for %s: PDO %p (=%p),ext %p, present %d, missing %d .\n",\r
+               p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, \r
+               p_dev_obj, p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) );\r
+\r
        /* Get the interface. */\r
        status = cl_fwd_query_ifc(\r
                p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack );\r
@@ -1239,6 +1352,47 @@ port_query_interface(
 }\r
 \r
 \r
+/* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
+static void\r
+__HibernateUpWorkItem(\r
+       IN                              DEVICE_OBJECT*                          p_dev_obj,\r
+       IN                              void*                                           context )\r
+{\r
+       IO_STACK_LOCATION       *p_io_stack;\r
+       bus_pdo_ext_t           *p_ext;\r
+       IRP                                     *p_irp;\r
+       POWER_STATE powerState;\r
+\r
+       BUS_ENTER( BUS_DBG_POWER );\r
+\r
+       p_ext = (bus_pdo_ext_t*)p_dev_obj->DeviceExtension;\r
+       p_irp = (IRP*)context;\r
+       p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+       IoFreeWorkItem( p_ext->p_po_work_item );\r
+       p_ext->p_po_work_item = NULL;\r
+\r
+       while (!p_ext->h_ca) {\r
+               BUS_TRACE( BUS_DBG_PNP, ("Waiting for the end of HCA registration ... \n"));\r
+               cl_thread_suspend( 200 );       /* suspend for 200 ms */\r
+       }\r
+\r
+       p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
+       powerState = PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
+\r
+       BUS_TRACE( BUS_DBG_POWER, \r
+               ("PoSetPowerState: old state %d, new state to %d\n", \r
+               powerState.DeviceState, p_ext->dev_po_state ));\r
+\r
+       p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+       PoStartNextPowerIrp( p_irp );\r
+       IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+       IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+\r
+       BUS_EXIT( BUS_DBG_POWER );\r
+}\r
+\r
+\r
 /*\r
  * The PDOs created by the IB Bus driver are software devices.  As such,\r
  * all power states are supported.  It is left to the HCA power policy\r
@@ -1250,6 +1404,7 @@ port_set_power(
        IN                              IRP* const                                      p_irp,\r
                OUT                     cl_irp_action_t* const          p_action )\r
 {\r
+       NTSTATUS                        status = STATUS_SUCCESS;\r
        IO_STACK_LOCATION       *p_io_stack;\r
        bus_pdo_ext_t           *p_ext;\r
 \r
@@ -1258,8 +1413,42 @@ port_set_power(
        p_ext = p_dev_obj->DeviceExtension;\r
        p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
 \r
+       BUS_TRACE( BUS_DBG_POWER, \r
+               ("SET_POWER for PDO %p (ext %p): type %s, state %d, action %d \n",\r
+               p_dev_obj, p_ext,\r
+               (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
+               p_io_stack->Parameters.Power.State.DeviceState, \r
+               p_io_stack->Parameters.Power.ShutdownType ));\r
+\r
+       if ((p_io_stack->Parameters.Power.Type == SystemPowerState) &&\r
+               (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate ||\r
+               p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 ))\r
+       {\r
+               BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj));\r
+               p_ext->b_hibernating = TRUE;\r
+       }\r
+\r
        if( p_io_stack->Parameters.Power.Type == DevicePowerState )\r
        {\r
+               /* after hibernation PDO is not ready for work. we need to wait for finishing of the HCA registration */\r
+               if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && p_ext->b_hibernating)\r
+               {\r
+                       /* Process in a work item - deregister_ca and HcaDeinit block. */\r
+                       ASSERT( !p_ext->p_po_work_item );\r
+                       p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj );\r
+                       if( !p_ext->p_po_work_item )\r
+                               status = STATUS_INSUFFICIENT_RESOURCES;\r
+                       else {\r
+                               /* Process in work item callback. */\r
+                               IoMarkIrpPending( p_irp );\r
+                               IoQueueWorkItem(\r
+                                       p_ext->p_po_work_item, __HibernateUpWorkItem, DelayedWorkQueue, p_irp );\r
+                               *p_action = IrpDoNothing;\r
+                               BUS_EXIT( BUS_DBG_POWER );\r
+                               return STATUS_PENDING;\r
+                       }\r
+               }\r
+\r
                /* Notify the power manager. */\r
                p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
                PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
@@ -1267,5 +1456,5 @@ port_set_power(
 \r
        *p_action = IrpComplete;\r
        BUS_EXIT( BUS_DBG_POWER );\r
-       return STATUS_SUCCESS;\r
+       return status;\r
 }\r
index c48169e..7409802 100644 (file)
@@ -203,6 +203,9 @@ cl_pnp(
 \r
        CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
 \r
+       CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
+               ("PDO %p, ext %p\n",  p_dev_obj, p_ext) );\r
+\r
        CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
        \r
        status = IoAcquireRemoveLock( &p_ext->remove_lock, p_irp );\r
index 6221696..4e8fc3b 100644 (file)
@@ -124,8 +124,9 @@ typedef struct _hca_dev_ext
        * ------------------------------------------------ */\r
        /* Cache of the system to device power states. */\r
        DEVICE_POWER_STATE              DevicePower[PowerSystemMaximum];\r
-       DEVICE_POWER_STATE              PowerState;                     /* state for Power Manager */\r
-       PIO_WORKITEM                                    pPoWorkItem;\r
+       DEVICE_POWER_STATE              DevicePowerState;\r
+       SYSTEM_POWER_STATE              SystemPowerState;\r
+       PIO_WORKITEM                    pPoWorkItem;\r
 \r
        /* -------------------------------------------------\r
        *               IB_AL DATA       \r
index f6753cb..4d9bf57 100644 (file)
@@ -467,6 +467,8 @@ __hca_deregister(
                        /* Release AL's CI interface. */\r
                        p_ext->ci_ifc.wdm.InterfaceDereference( p_ext->ci_ifc.wdm.Context );\r
                        p_ext->state = HCA_STARTED;\r
+                       HCA_PRINT( TRACE_LEVEL_INFORMATION      ,HCA_DBG_PNP,\r
+                               ("***** HCA deregistered \n"));\r
                }\r
        }\r
 \r
@@ -493,17 +495,18 @@ __hca_register(
        status = __get_ci_interface( p_dev_obj );\r
        if( !NT_SUCCESS( status ) )\r
        {\r
-               HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_SHIM\r
+               HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP\r
                        ("__get_ci_interface returned %08x.\n", status));\r
-               return status;\r
+               goto exit;\r
        }\r
 \r
        /* Allocate and populate our HCA interface structure. */\r
        p_hca_ifc = __alloc_hca_ifc( p_ext );\r
        if( !p_hca_ifc )\r
        {\r
-               HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,("__alloc_hca_ifc failed.\n"));\r
-               return STATUS_NO_MEMORY;\r
+               HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("__alloc_hca_ifc failed.\n"));\r
+               status = STATUS_NO_MEMORY;\r
+               goto exit;\r
        }\r
 \r
        /* Notify AL that we're available... */\r
@@ -512,11 +515,16 @@ __hca_register(
        if( ib_status != IB_SUCCESS )\r
        {\r
                p_ext->ci_ifc.wdm.InterfaceDereference( p_ext->ci_ifc.wdm.Context );\r
-               return STATUS_INSUFFICIENT_RESOURCES;\r
+               status = STATUS_INSUFFICIENT_RESOURCES;\r
+               goto exit;\r
        }\r
 \r
        p_ext->state = HCA_REGISTERED;\r
-       return STATUS_SUCCESS;\r
+       HCA_PRINT( TRACE_LEVEL_INFORMATION  ,HCA_DBG_PNP,\r
+               ("***** HCA registered \n"));\r
+exit:\r
+       HCA_EXIT( HCA_DBG_PNP );\r
+       return status;\r
 }\r
 \r
 \r
@@ -783,7 +791,7 @@ hca_start(
        if( !NT_SUCCESS( status ) )\r
        {\r
                HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
-                       ("Lower drivers failed IRP_MN_START_DEVICE.\n"));\r
+                       ("Lower drivers failed IRP_MN_START_DEVICE (%#x).\n", status));\r
                return status;\r
        }\r
 \r
@@ -883,9 +891,13 @@ hca_start(
        }\r
 \r
        /* We get started fully powered. */\r
-       p_ext->PowerState = PowerDeviceD0;\r
+       p_ext->DevicePowerState = PowerDeviceD0;\r
        powerState.DeviceState = PowerDeviceD0;\r
-       PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState );\r
+       powerState = PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState );\r
+       HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, \r
+               ("PoSetPowerState: old state %d, new state to %d\n", \r
+               powerState.DeviceState, p_ext->DevicePowerState ));\r
+\r
 \r
        {\r
                struct mthca_dev *mdev = p_ext->hca.mdev;\r
@@ -978,7 +990,7 @@ hca_release_resources(
        IN                              DEVICE_OBJECT* const            p_dev_obj )\r
 {\r
        hca_dev_ext_t           *p_ext;\r
-       POWER_STATE                     powerState;\r
+       POWER_STATE             powerState;\r
 \r
        HCA_ENTER( HCA_DBG_PNP );\r
 \r
@@ -988,8 +1000,14 @@ hca_release_resources(
        __hca_release_resources(p_dev_obj);\r
 \r
        /* Notify the power manager that the device is powered down. */\r
+       p_ext->DevicePowerState = PowerDeviceD3;\r
        powerState.DeviceState = PowerDeviceD3;\r
-       PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState );\r
+       powerState = PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState );\r
+\r
+       HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, \r
+               ("PoSetPowerState: old state %d, new state to %d\n", \r
+               powerState.DeviceState, p_ext->DevicePowerState ));\r
+\r
 \r
        /* Clear the PnP state in case we get restarted. */\r
        p_ext->pnpState = 0;\r
@@ -1246,7 +1264,6 @@ hca_query_pnp_state(
        return STATUS_SUCCESS;;\r
 }\r
 \r
-\r
 static NTSTATUS\r
 hca_query_power(\r
        IN                              DEVICE_OBJECT* const            p_dev_obj,\r
@@ -1262,15 +1279,30 @@ hca_query_power(
 \r
        pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
 \r
+       HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
+               ("QUERY_POWER for FDO %p: type %s, state %d, action %d, IRQL %d, IRP %p\n",\r
+               p_dev_obj, \r
+               (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
+               pIoStack->Parameters.Power.State.DeviceState, \r
+               pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql(), p_irp ));\r
+\r
        switch( pIoStack->Parameters.Power.Type )\r
        {\r
        case SystemPowerState:\r
                /* Fail any requests to hibernate or sleep the system. */\r
                switch( pIoStack->Parameters.Power.State.SystemState )\r
                {\r
+                       case PowerSystemSleeping1:      // STANDBY support\r
+                       case PowerSystemHibernate:\r
+                       {\r
+                               hca_dev_ext_t*p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
+                               if (atomic_read(&p_ext->usecnt)) \r
+                                       status = STATUS_UNSUCCESSFUL;\r
+                               break;\r
+                       }\r
+\r
                        case PowerSystemWorking:\r
                        case PowerSystemShutdown:\r
-                               /* We only support fully working and shutdown system states. */\r
                                break;\r
 \r
                        default:\r
@@ -1293,10 +1325,10 @@ hca_query_power(
                break;\r
        }\r
 \r
-       if( status == STATUS_NOT_SUPPORTED )\r
-               *p_action = IrpComplete;\r
-       else\r
+       if( status == STATUS_SUCCESS )\r
                *p_action = IrpSkip;\r
+       else\r
+               *p_action = IrpComplete;\r
 \r
        HCA_EXIT( HCA_DBG_PO );\r
        return status;\r
@@ -1345,7 +1377,7 @@ __SystemPowerCompletion(
        hca_dev_ext_t           *p_ext;\r
        IO_STACK_LOCATION       *pIoStack;\r
 \r
-       HCA_ENTER( HCA_DBG_PNP );\r
+       HCA_ENTER( HCA_DBG_PO );\r
 \r
        UNUSED_PARAM( context );\r
 \r
@@ -1354,12 +1386,12 @@ __SystemPowerCompletion(
 \r
        if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
        {\r
-               PoStartNextPowerIrp( p_irp );\r
-               IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
-               HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
+               HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
                        ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
                        p_irp->IoStatus.Status));\r
-               return STATUS_SUCCESS;\r
+               status = STATUS_SUCCESS;\r
+               PoStartNextPowerIrp( p_irp );\r
+               goto release;\r
        }\r
 \r
        state.DeviceState = \r
@@ -1372,25 +1404,33 @@ __SystemPowerCompletion(
        status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
                __RequestPowerCompletion, p_irp, NULL );\r
 \r
-       if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
-       {\r
+       HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
+               ("PoRequestPowerIrp: SET_POWER 'PowerDeviceD%d', status %#x\n", \r
+               state.DeviceState - 1, status ));\r
+\r
+       if( status != STATUS_PENDING ) {\r
+               HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO,\r
+                       ("PoRequestPowerIrp returned %08x.\n", status));\r
+               p_irp->IoStatus.Status = status;        /* Propagate the failure. */\r
                PoStartNextPowerIrp( p_irp );\r
-               /* Propagate the failure. */\r
-               p_irp->IoStatus.Status = status;\r
                IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
-               IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
-               HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
-                       ("PoRequestPowerIrp returned %08x.\n", status));\r
+               goto release;\r
        }\r
 \r
-       HCA_EXIT( HCA_DBG_PNP );\r
-       return STATUS_MORE_PROCESSING_REQUIRED;\r
+       status = STATUS_MORE_PROCESSING_REQUIRED;\r
+       goto exit;\r
+\r
+release:       \r
+       IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+exit:\r
+       HCA_EXIT( HCA_DBG_PO );\r
+       return status;\r
 }\r
 \r
 \r
 /* Work item callback to handle DevicePowerD0 IRPs at passive level. */\r
 static void\r
-__PowerUpCb(\r
+__DevicePowerUpCompletionWorkItem(\r
        IN                              DEVICE_OBJECT*                          p_dev_obj,\r
        IN                              void*                                           context )\r
 {\r
@@ -1398,6 +1438,7 @@ __PowerUpCb(
        IO_STACK_LOCATION       *pIoStack;\r
        hca_dev_ext_t           *p_ext;\r
        IRP                                     *p_irp;\r
+       POWER_STATE powerState;\r
 \r
        HCA_ENTER( HCA_DBG_PO );\r
 \r
@@ -1409,32 +1450,50 @@ __PowerUpCb(
        p_ext->pPoWorkItem = NULL;\r
 \r
        /* restart the HCA */\r
+       HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
+               ("***** Restart the HCA, IRQL %d\n", KeGetCurrentIrql()));\r
+\r
        status = mthca_init_one( p_ext );\r
-       if( !NT_SUCCESS( status ) )\r
-               goto done;\r
+       if( !NT_SUCCESS( status ) ) {\r
+               HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
+                       ("!!! mthca_init_one failed (%#x) \n", status));\r
+               goto err_mthca_init;\r
+       }\r
 \r
-       if( p_ext->p_al_dev )\r
+       if( p_ext->p_al_dev ) {\r
                status = __hca_register( p_dev_obj );\r
-\r
-done:\r
-       if( !NT_SUCCESS( status ) )\r
-       {\r
-               /* Flag device as having failed. */\r
-               p_ext->pnpState |= PNP_DEVICE_FAILED;\r
-               IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
+               if( !NT_SUCCESS( status ) ) {\r
+                       HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
+                               ("!!! __hca_register failed (%#x) \n", status));\r
+                       goto err_hca_reg;\r
+               }\r
        }\r
 \r
+       p_ext->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState;\r
+       powerState = PoSetPowerState( p_dev_obj, DevicePowerState,\r
+               pIoStack->Parameters.Power.State );\r
+\r
+       HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
+               ("PoSetPowerState: old state %d, new state to %d\n", \r
+               powerState.DeviceState, p_ext->DevicePowerState ));\r
+\r
+       goto exit;\r
+\r
+err_hca_reg:\r
+err_mthca_init:\r
+       /* Flag device as having failed. */\r
+       p_ext->pnpState |= PNP_DEVICE_FAILED;\r
+       IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
+exit:\r
        PoStartNextPowerIrp( p_irp );\r
        IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
        IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
-\r
        HCA_EXIT( HCA_DBG_PO );\r
 }\r
 \r
-\r
 /*NOTE: Completion routines must NEVER be pageable. */\r
 static NTSTATUS\r
-__DevicePowerCompletion(\r
+__DevicePowerUpCompletion(\r
        IN                              DEVICE_OBJECT                           *p_dev_obj,\r
        IN                              IRP                                                     *p_irp,\r
        IN                              void                                            *context )\r
@@ -1442,9 +1501,6 @@ __DevicePowerCompletion(
        NTSTATUS                        status = STATUS_SUCCESS;\r
        hca_dev_ext_t           *p_ext;\r
        IO_STACK_LOCATION       *pIoStack;\r
-       KIRQL irql = KeGetCurrentIrql(  );\r
-       \r
-       \r
 \r
        HCA_ENTER( HCA_DBG_PO );\r
 \r
@@ -1453,61 +1509,43 @@ __DevicePowerCompletion(
        p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
        pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
 \r
-       if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
-       {\r
-               PoStartNextPowerIrp( p_irp );\r
-               IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
-               HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
+       if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) {\r
+               HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
                        ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n",\r
                        p_irp->IoStatus.Status));\r
-               return STATUS_SUCCESS;\r
-       }\r
-\r
-       p_ext->PowerState = pIoStack->Parameters.Power.State.DeviceState;\r
-       PoSetPowerState( p_dev_obj, DevicePowerState,\r
-               pIoStack->Parameters.Power.State );\r
-\r
-       if (irql > PASSIVE_LEVEL) {\r
-               /* Process in a work item - mthca_start blocks. */\r
-               ASSERT( !p_ext->pPoWorkItem );\r
-               p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
-               if( !p_ext->pPoWorkItem )\r
-               {\r
-                       IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
-\r
-                       PoStartNextPowerIrp( p_irp );\r
-                       IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
-\r
-                       return STATUS_SUCCESS;\r
-               }\r
-\r
-               /* Process in work item callback. */\r
-               IoMarkIrpPending( p_irp );\r
-               IoQueueWorkItem( p_ext->pPoWorkItem, __PowerUpCb, DelayedWorkQueue, p_irp );\r
+               status =  STATUS_SUCCESS;\r
+               PoStartNextPowerIrp( p_irp );\r
+               goto release;\r
        }\r
-       else {\r
-\r
-               /* restart the HCA */\r
-               status = mthca_init_one( p_ext );\r
-               if( !NT_SUCCESS( status ) )\r
-                       goto done;\r
 \r
-               if( p_ext->p_al_dev )\r
-                       status = __hca_register( p_dev_obj );\r
+       /* Process in a work item - mthca_start blocks. */\r
+       ASSERT( !p_ext->pPoWorkItem );\r
+       p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
+       if( !p_ext->pPoWorkItem ) {\r
+               HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
+                       ("Failed to allocate work item.\n" ));\r
+               status = STATUS_SUCCESS;\r
+               p_ext->pnpState |= PNP_DEVICE_FAILED;\r
+               IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
+               PoStartNextPowerIrp( p_irp );\r
+               goto release;\r
        }\r
 \r
-done:\r
-       if( !NT_SUCCESS( status ) )\r
-               IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
+       /* Process in work item callback. */\r
+       IoMarkIrpPending( p_irp );\r
+       IoQueueWorkItem( p_ext->pPoWorkItem, \r
+               __DevicePowerUpCompletionWorkItem, DelayedWorkQueue, p_irp );\r
+       status = STATUS_MORE_PROCESSING_REQUIRED;\r
+       goto exit;\r
 \r
-       PoStartNextPowerIrp( p_irp );\r
+release:       \r
        IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
-\r
+exit:  \r
        HCA_EXIT( HCA_DBG_PO );\r
-       return STATUS_MORE_PROCESSING_REQUIRED;\r
+       return status;\r
 }\r
 \r
-static NTSTATUS __DeviceDownCbCompletion(\r
+static NTSTATUS __DevicePowerDownWorkItemCompletion(\r
        IN                              DEVICE_OBJECT   *p_dev_obj,\r
        IN                              IRP                             *p_irp,\r
        IN                              void                            *context )\r
@@ -1515,20 +1553,25 @@ static NTSTATUS __DeviceDownCbCompletion(
        hca_dev_ext_t  *p_ext  = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
        UNUSED_PARAM( context );\r
 \r
+       HCA_ENTER( HCA_DBG_PO );\r
+\r
        PoStartNextPowerIrp( p_irp );\r
        IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+\r
+       HCA_EXIT( HCA_DBG_PO );\r
        return STATUS_SUCCESS;\r
 }\r
 \r
 /* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
 static void\r
-__PowerDownCb(\r
+__DevicePowerDownWorkItem(\r
        IN                              DEVICE_OBJECT*                          p_dev_obj,\r
        IN                              void*                                           context )\r
 {\r
        IO_STACK_LOCATION       *pIoStack;\r
        hca_dev_ext_t           *p_ext;\r
        IRP                                     *p_irp;\r
+       POWER_STATE powerState;\r
 \r
        HCA_ENTER( HCA_DBG_PO );\r
 \r
@@ -1539,15 +1582,25 @@ __PowerDownCb(
        IoFreeWorkItem( p_ext->pPoWorkItem );\r
        p_ext->pPoWorkItem = NULL;\r
 \r
-       PoSetPowerState( p_dev_obj, DevicePowerState,\r
+       p_ext->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState;\r
+       powerState = PoSetPowerState( p_dev_obj, DevicePowerState,\r
                pIoStack->Parameters.Power.State );\r
 \r
-       __hca_deregister( p_ext );\r
-       mthca_remove_one( p_ext );\r
+       HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
+               ("PoSetPowerState: old state %d, new state to %d, IRQL %d\n", \r
+               powerState.DeviceState, p_ext->DevicePowerState, KeGetCurrentIrql() ));\r
+\r
+       HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
+               ("***** Remove the HCA \n"));\r
+\r
+       {\r
+               __hca_deregister( p_ext );\r
+               mthca_remove_one( p_ext );\r
+       }\r
 \r
        IoCopyCurrentIrpStackLocationToNext( p_irp );\r
 #pragma warning( push, 3 )\r
-       IoSetCompletionRoutine( p_irp, __DeviceDownCbCompletion,\r
+       IoSetCompletionRoutine( p_irp, __DevicePowerDownWorkItemCompletion,\r
                NULL, TRUE, TRUE, TRUE );\r
 #pragma warning( pop )\r
        PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
@@ -1571,9 +1624,18 @@ hca_set_power(
        p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
        pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
 \r
+       HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
+               ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d, IRQL %d \n",\r
+               p_dev_obj, p_ext,\r
+               (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
+               pIoStack->Parameters.Power.State.DeviceState, \r
+               pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql() ));\r
+\r
        switch( pIoStack->Parameters.Power.Type )\r
        {\r
        case SystemPowerState:\r
+               p_ext->SystemPowerState = pIoStack->Parameters.Power.State.SystemState;\r
+               \r
                /*\r
                 * Process on the way up the stack.  We cannot block since the \r
                 * power dispatch function can be called at elevated IRQL if the\r
@@ -1593,10 +1655,11 @@ hca_set_power(
 \r
        case DevicePowerState:\r
                IoMarkIrpPending( p_irp );\r
-               if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 )\r
-               {\r
+               if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 && \r
+                       p_ext->SystemPowerState == PowerSystemWorking)\r
+               { /* power up */\r
                        /* If we're already powered up, just pass down. */\r
-                       if( p_ext->PowerState == PowerDeviceD0 )\r
+                       if( p_ext->DevicePowerState == PowerDeviceD0 )\r
                        {\r
                                status = STATUS_SUCCESS;\r
                                *p_action = IrpIgnore;\r
@@ -1606,13 +1669,14 @@ hca_set_power(
                        /* Process in I/O completion callback. */\r
                        IoCopyCurrentIrpStackLocationToNext( p_irp );\r
 #pragma warning( push, 3 )\r
-                       IoSetCompletionRoutine( p_irp, __DevicePowerCompletion, NULL, \r
+                       IoSetCompletionRoutine( p_irp, __DevicePowerUpCompletion, NULL, \r
                                TRUE, TRUE, TRUE );\r
 #pragma warning( pop )\r
                        PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
                }\r
                else\r
-               {\r
+               { /* power down */\r
+\r
                        /* Process in a work item - deregister_ca and HcaDeinit block. */\r
                        ASSERT( !p_ext->pPoWorkItem );\r
                        p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
@@ -1623,9 +1687,8 @@ hca_set_power(
                        }\r
 \r
                        /* Process in work item callback. */\r
-                       IoMarkIrpPending( p_irp );\r
                        IoQueueWorkItem(\r
-                               p_ext->pPoWorkItem, __PowerDownCb, DelayedWorkQueue, p_irp );\r
+                               p_ext->pPoWorkItem, __DevicePowerDownWorkItem, DelayedWorkQueue, p_irp );\r
                }\r
                *p_action = IrpDoNothing;\r
                status = STATUS_PENDING;\r
index 7ecba1b..2ea169d 100644 (file)
@@ -383,8 +383,11 @@ static int mthca_cmd_wait(struct mthca_dev *dev,
                             out_param ? *out_param : 0,
                             in_modifier, op_modifier,
                             op, context->token, 1);
-       if (err)
+       if (err) {
+               HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_LOW,
+                       ("mthca_cmd_wait: Command %02x completed with err %02x\n", op, err));
                goto out;
+       }
 
        {
                NTSTATUS res;
@@ -393,13 +396,15 @@ static int mthca_cmd_wait(struct mthca_dev *dev,
                res = KeWaitForSingleObject( &context->event, Executive, KernelMode, FALSE,  &interval );
                if (res != STATUS_SUCCESS) {
                        err = -EBUSY;
+                       HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_LOW,
+                               ("mthca_cmd_wait: Command %02x completed with err %02x\n", op, err));
                        goto out;
                }
        }
 
        *status = context->status;
        if (*status)
-               HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("mthca_cmd_wait: Command %02x completed with status %02x\n",
+               HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_LOW,("mthca_cmd_wait: Command %02x completed with status %02x\n",
                          op, *status));
 
        if (out_is_imm)