Create Witherspoon fan errors

Moved the code to create NotPresent and Nonfunctional errors to a new
yaml, fan-errors.yaml.
Fixed the problem with duplicate errors, caused by a 2nd fan
going nonfunctional or not present which would create a 2nd error
for the 1st fan previously nonfunctional or not present.

Create a notpresent error if fan 0, 1, 2, or 3 is not present for more
than 20 seconds. Create a Nonfunctional error if fan 0, 1, 2, or 3 is not
functional for any amount of time.
The system must be powered on in both of these cases.
If a water cooled system, don't create errors for fan 1.
An error is created each time the chassis powers on if a fan is
removed or nonfunctional.

Resolves openbmc/openbmc#2472

Change-Id: Ibd71bf3a3b2381df623e7310a510a2f044c525e4
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
diff --git a/meta-witherspoon/recipes-phosphor/fans/witherspoon-fan-policy/fan-errors.yaml b/meta-witherspoon/recipes-phosphor/fans/witherspoon-fan-policy/fan-errors.yaml
new file mode 100644
index 0000000..1fa1530
--- /dev/null
+++ b/meta-witherspoon/recipes-phosphor/fans/witherspoon-fan-policy/fan-errors.yaml
@@ -0,0 +1,541 @@
+# Witherspoon fan error policy for PDM.
+#
+# Create a NotPresent error if fan 0, 1, 2, or 3 is not present for more
+# than 20 seconds. Create a Nonfunctional error if fan 0, 1, 2, or 3 is not
+# functional for any amount of time.
+# The system must be powered on in both of these cases.
+# If a water cooled system, don't create errors for fan 1.
+# Note: An error is created each time the chassis powers on.
+
+- name: fan0
+  class: group
+  group: path
+  members:
+    - meta: FAN
+      path: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan0
+
+- name: fan1
+  class: group
+  group: path
+  members:
+    - meta: FAN
+      path: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan1
+
+- name: fan2
+  class: group
+  group: path
+  members:
+    - meta: FAN
+      path: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan2
+
+- name: fan3
+  class: group
+  group: path
+  members:
+    - meta: FAN
+      path: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan3
+
+- name: chassis state
+  description: >
+    'Witherspoon has a single chassis to monitor.'
+  class: group
+  group: path
+  members:
+    - meta: CHASSISSTATE
+      path: /xyz/openbmc_project/state/chassis0
+
+- name: chassis
+  description: >
+    'Witherspoon has a single chassis to monitor.'
+  class: group
+  group: path
+  members:
+    - meta: CHASSIS
+      path: /xyz/openbmc_project/inventory/system/chassis
+
+
+- name: fan present
+  description: >
+    'Monitor the presence state of each fan.'
+  class: group
+  group: property
+  type: boolean
+  members:
+    - interface: xyz.openbmc_project.Inventory.Item
+      meta: PRESENT
+      property: Present
+
+- name: fan functional
+  description: >
+    'Monitor the functional state of each fan.'
+  class: group
+  group: property
+  type: boolean
+  members:
+    - interface: xyz.openbmc_project.State.Decorator.OperationalStatus
+      meta: FUNCTIONAL
+      property: Functional
+
+- name: chassis powered
+  description: >
+    'Monitor the chassis power state.'
+  class: group
+  group: property
+  type: string
+  members:
+    - interface: xyz.openbmc_project.State.Chassis
+      meta: CHASSIS_STATE
+      property: CurrentPowerState
+
+- name: chassis air cooled
+  description: >
+    'The chassis cooling type.'
+  class: group
+  group: property
+  type: boolean
+  members:
+    - interface: xyz.openbmc_project.Inventory.Decorator.CoolingType
+      meta: COOLING_TYPE
+      property: WaterCooled
+
+- name: watch chassis state
+  description: >
+    'Trigger logic on chassis power state changes.'
+  class: watch
+  watch: property
+  paths: chassis state
+  properties: chassis powered
+  callback: check power
+
+- name: watch fan0 presence
+  description: >
+    'Trigger logic on fan0 presence state changes.'
+  class: watch
+  watch: property
+  paths: fan0
+  properties: fan present
+  callback: check power fan0 presence
+
+- name: watch fan0 functional
+  description: >
+    'Trigger logic on fan0 functional state changes.'
+  class: watch
+  watch: property
+  paths: fan0
+  properties: fan functional
+  callback: check power fan0 functional
+
+- name: watch fan1 presence
+  description: >
+    'Trigger logic on fan1 presence state changes.'
+  class: watch
+  watch: property
+  paths: fan1
+  properties: fan present
+  callback: check power fan1 presence
+
+- name: watch fan1 functional
+  description: >
+    'Trigger logic on fan1 functional state changes.'
+  class: watch
+  watch: property
+  paths: fan1
+  properties: fan functional
+  callback: check power fan1 functional
+
+- name: watch fan2 presence
+  description: >
+    'Trigger logic on fan2 presence state changes.'
+  class: watch
+  watch: property
+  paths: fan2
+  properties: fan present
+  callback: check power fan2 presence
+
+- name: watch fan2 functional
+  description: >
+    'Trigger logic on fan2 functional state changes.'
+  class: watch
+  watch: property
+  paths: fan2
+  properties: fan functional
+  callback: check power fan2 functional
+
+- name: watch fan3 presence
+  description: >
+    'Trigger logic on fan3 presence state changes.'
+  class: watch
+  watch: property
+  paths: fan3
+  properties: fan present
+  callback: check power fan3 presence
+
+- name: watch fan3 functional
+  description: >
+    'Trigger logic on fan3 functional state changes.'
+  class: watch
+  watch: property
+  paths: fan3
+  properties: fan functional
+  callback: check power fan3 functional
+
+- name: check power
+  description: >
+    'If the chassis has power, check all fans.'
+  class: condition
+  condition: count
+  paths: chassis state
+  properties: chassis powered
+  callback: check fans
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: xyz.openbmc_project.State.Chassis.PowerState.On
+
+- name: check power fan0 presence
+  description: >
+    'If the chassis has power, check presence of fan0.'
+  class: condition
+  condition: count
+  paths: chassis state
+  properties: chassis powered
+  callback: check fan0 presence
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: xyz.openbmc_project.State.Chassis.PowerState.On
+
+- name: check power fan0 functional
+  description: >
+    'If the chassis has power, check functional of fan0.'
+  class: condition
+  condition: count
+  paths: chassis state
+  properties: chassis powered
+  callback: check fan0 functional
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: xyz.openbmc_project.State.Chassis.PowerState.On
+
+- name: check power fan1 presence
+  description: >
+    'If the chassis has power, check presence of fan1.'
+  class: condition
+  condition: count
+  paths: chassis state
+  properties: chassis powered
+  callback: check fan1 presence
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: xyz.openbmc_project.State.Chassis.PowerState.On
+
+- name: check power fan1 functional
+  description: >
+    'If the chassis has power, check functional of fan1.'
+  class: condition
+  condition: count
+  paths: chassis state
+  properties: chassis powered
+  callback: check fan1 functional
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: xyz.openbmc_project.State.Chassis.PowerState.On
+
+- name: check power fan2 presence
+  description: >
+    'If the chassis has power, check presence of fan2.'
+  class: condition
+  condition: count
+  paths: chassis state
+  properties: chassis powered
+  callback: check fan2 presence
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: xyz.openbmc_project.State.Chassis.PowerState.On
+
+- name: check power fan2 functional
+  description: >
+    'If the chassis has power, check functional of fan2.'
+  class: condition
+  condition: count
+  paths: chassis state
+  properties: chassis powered
+  callback: check fan2 functional
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: xyz.openbmc_project.State.Chassis.PowerState.On
+
+- name: check power fan3 presence
+  description: >
+    'If the chassis has power, check presence of fan3.'
+  class: condition
+  condition: count
+  paths: chassis state
+  properties: chassis powered
+  callback: check fan3 presence
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: xyz.openbmc_project.State.Chassis.PowerState.On
+
+- name: check power fan3 functional
+  description: >
+    'If the chassis has power, check functional of fan3.'
+  class: condition
+  condition: count
+  paths: chassis state
+  properties: chassis powered
+  callback: check fan3 functional
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: xyz.openbmc_project.State.Chassis.PowerState.On
+
+- name: check fans
+  description: >
+    'Verify each of the 3 fans are present.'
+  class: callback
+  callback: group
+  members:
+    - check fan0 presence
+    - check fan1 presence
+    - check fan2 presence
+    - check fan3 presence
+    - check fan0 functional
+    - check fan1 functional
+    - check fan2 functional
+    - check fan3 functional
+
+- name: check fan0 presence
+  description: >
+    'If this condition passes fan0 has been unplugged for more than 20 seconds.'
+  class: condition
+  condition: count
+  paths: fan0
+  properties: fan present
+  defer: 20000000us
+  callback: notpresent fan0 error
+  countop: '<'
+  countbound: 1
+  op: '=='
+  bound: true
+
+- name: check fan0 functional
+  description: >
+    'If this condition passes fan0 has been marked as nonfunctional.'
+  class: condition
+  condition: count
+  paths: fan0
+  properties: fan functional
+  callback: nonfunctional fan0 error
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: false
+
+- name: check fan1 presence
+  description: >
+    'If this condition passes fan1 has been unplugged for more than 20 seconds.
+     Fan 1 is not in a water cooled Witherspoon, so check for cooling type
+     before creating an error.'
+  class: condition
+  condition: count
+  paths: fan1
+  properties: fan present
+  defer: 20000000us
+  callback: check cooling type notpresent error
+  countop: '<'
+  countbound: 1
+  op: '=='
+  bound: true
+
+- name: check fan1 functional
+  description: >
+    'If this condition passes fan1 has been marked as nonfunctional.
+     Fan 1 is not in a water cooled Witherspoon, so check for cooling type
+     before creating an error.'
+  class: condition
+  condition: count
+  paths: fan1
+  properties: fan functional
+  callback: check cooling type nonfunctional error
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: false
+
+- name: check fan2 presence
+  description: >
+    'If this condition passes fan2 has been unplugged for more than 20 seconds.'
+  class: condition
+  condition: count
+  paths: fan2
+  properties: fan present
+  defer: 20000000us
+  callback: notpresent fan2 error
+  countop: '<'
+  countbound: 1
+  op: '=='
+  bound: true
+
+- name: check fan2 functional
+  description: >
+    'If this condition passes fan2 has been marked as nonfunctional.'
+  class: condition
+  condition: count
+  paths: fan2
+  properties: fan functional
+  callback: nonfunctional fan2 error
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: false
+
+- name: check fan3 presence
+  description: >
+    'If this condition passes fan3 has been unplugged for more than 20 seconds.'
+  class: condition
+  condition: count
+  paths: fan3
+  properties: fan present
+  defer: 20000000us
+  callback: notpresent fan3 error
+  countop: '<'
+  countbound: 1
+  op: '=='
+  bound: true
+
+- name: check fan3 functional
+  description: >
+    'If this condition passes fan3 has been marked as nonfunctional.'
+  class: condition
+  condition: count
+  paths: fan3
+  properties: fan functional
+  callback: nonfunctional fan3 error
+  countop: '>'
+  countbound: 0
+  op: '=='
+  bound: false
+
+- name: check cooling type nonfunctional error
+  description: >
+    'If this condition passes the chassis is air cooled and will create a
+     nonfunctional error for fan 1.'
+  class: condition
+  condition: count
+  paths: chassis
+  properties: chassis air cooled
+  callback: nonfunctional fan1 error
+  countop: '=='
+  countbound: 0
+  op: '=='
+  bound: true
+
+- name: check cooling type notpresent error
+  description: >
+    'If this condition passes the chassis is air cooled and will create a
+     notpresent error for fan 1.'
+  class: condition
+  condition: count
+  paths: chassis
+  properties: chassis air cooled
+  callback: notpresent fan1 error
+  countop: '=='
+  countbound: 0
+  op: '=='
+  bound: true
+
+- name: notpresent fan0 error
+  class: callback
+  callback: elog
+  paths: fan0
+  properties: fan present
+  error: xyz::openbmc_project::Inventory::Error::NotPresent
+  metadata:
+    - name: xyz::openbmc_project::Inventory::NotPresent::CALLOUT_INVENTORY_PATH
+      value: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan0
+      type: string
+
+- name: nonfunctional fan0 error
+  class: callback
+  callback: elog
+  paths: fan0
+  properties: fan functional
+  error: xyz::openbmc_project::Inventory::Error::Nonfunctional
+  metadata:
+    - name: xyz::openbmc_project::Inventory::Nonfunctional::CALLOUT_INVENTORY_PATH
+      value: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan0
+      type: string
+
+- name: notpresent fan1 error
+  class: callback
+  callback: elog
+  paths: fan1
+  properties: fan present
+  error: xyz::openbmc_project::Inventory::Error::NotPresent
+  metadata:
+    - name: xyz::openbmc_project::Inventory::NotPresent::CALLOUT_INVENTORY_PATH
+      value: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan1
+      type: string
+
+- name: nonfunctional fan1 error
+  class: callback
+  callback: elog
+  paths: fan1
+  properties: fan functional
+  error: xyz::openbmc_project::Inventory::Error::Nonfunctional
+  metadata:
+    - name: xyz::openbmc_project::Inventory::Nonfunctional::CALLOUT_INVENTORY_PATH
+      value: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan1
+      type: string
+
+- name: notpresent fan2 error
+  class: callback
+  callback: elog
+  paths: fan2
+  properties: fan present
+  error: xyz::openbmc_project::Inventory::Error::NotPresent
+  metadata:
+    - name: xyz::openbmc_project::Inventory::NotPresent::CALLOUT_INVENTORY_PATH
+      value: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan2
+      type: string
+
+- name: nonfunctional fan2 error
+  class: callback
+  callback: elog
+  paths: fan2
+  properties: fan functional
+  error: xyz::openbmc_project::Inventory::Error::Nonfunctional
+  metadata:
+    - name: xyz::openbmc_project::Inventory::Nonfunctional::CALLOUT_INVENTORY_PATH
+      value: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan2
+      type: string
+
+- name: notpresent fan3 error
+  class: callback
+  callback: elog
+  paths: fan3
+  properties: fan present
+  error: xyz::openbmc_project::Inventory::Error::NotPresent
+  metadata:
+    - name: xyz::openbmc_project::Inventory::NotPresent::CALLOUT_INVENTORY_PATH
+      value: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan3
+      type: string
+
+- name: nonfunctional fan3 error
+  class: callback
+  callback: elog
+  paths: fan3
+  properties: fan functional
+  error: xyz::openbmc_project::Inventory::Error::Nonfunctional
+  metadata:
+    - name: xyz::openbmc_project::Inventory::Nonfunctional::CALLOUT_INVENTORY_PATH
+      value: /xyz/openbmc_project/inventory/system/chassis/motherboard/fan3
+      type: string
+