|
@@ -176,6 +176,18 @@ static int ap_apft_available(void)
|
|
return test_facility(15);
|
|
return test_facility(15);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * ap_qact_available(): Test if the PQAP(QACT) subfunction is available.
|
|
|
|
+ *
|
|
|
|
+ * Returns 1 if the QACT subfunction is available.
|
|
|
|
+ */
|
|
|
|
+static inline int ap_qact_available(void)
|
|
|
|
+{
|
|
|
|
+ if (ap_configuration)
|
|
|
|
+ return ap_configuration->qact;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* ap_test_queue(): Test adjunct processor queue.
|
|
* ap_test_queue(): Test adjunct processor queue.
|
|
* @qid: The AP queue number
|
|
* @qid: The AP queue number
|
|
@@ -987,6 +999,47 @@ static int ap_select_domain(void)
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * This function checks the type and returns either 0 for not
|
|
|
|
+ * supported or the highest compatible type value (which may
|
|
|
|
+ * include the input type value).
|
|
|
|
+ */
|
|
|
|
+static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func)
|
|
|
|
+{
|
|
|
|
+ int comp_type = 0;
|
|
|
|
+
|
|
|
|
+ /* < CEX2A is not supported */
|
|
|
|
+ if (rawtype < AP_DEVICE_TYPE_CEX2A)
|
|
|
|
+ return 0;
|
|
|
|
+ /* up to CEX6 known and fully supported */
|
|
|
|
+ if (rawtype <= AP_DEVICE_TYPE_CEX6)
|
|
|
|
+ return rawtype;
|
|
|
|
+ /*
|
|
|
|
+ * unknown new type > CEX6, check for compatibility
|
|
|
|
+ * to the highest known and supported type which is
|
|
|
|
+ * currently CEX6 with the help of the QACT function.
|
|
|
|
+ */
|
|
|
|
+ if (ap_qact_available()) {
|
|
|
|
+ struct ap_queue_status status;
|
|
|
|
+ struct ap_qact_ap_info apinfo = {0};
|
|
|
|
+
|
|
|
|
+ apinfo.mode = (func >> 26) & 0x07;
|
|
|
|
+ apinfo.cat = AP_DEVICE_TYPE_CEX6;
|
|
|
|
+ status = ap_qact(qid, 0, &apinfo);
|
|
|
|
+ if (status.response_code == AP_RESPONSE_NORMAL
|
|
|
|
+ && apinfo.cat >= AP_DEVICE_TYPE_CEX2A
|
|
|
|
+ && apinfo.cat <= AP_DEVICE_TYPE_CEX6)
|
|
|
|
+ comp_type = apinfo.cat;
|
|
|
|
+ }
|
|
|
|
+ if (!comp_type)
|
|
|
|
+ AP_DBF(DBF_WARN, "queue=%02x.%04x unable to map type %d\n",
|
|
|
|
+ AP_QID_CARD(qid), AP_QID_QUEUE(qid), rawtype);
|
|
|
|
+ else if (comp_type != rawtype)
|
|
|
|
+ AP_DBF(DBF_INFO, "queue=%02x.%04x map type %d to %d\n",
|
|
|
|
+ AP_QID_CARD(qid), AP_QID_QUEUE(qid), rawtype, comp_type);
|
|
|
|
+ return comp_type;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* helper function to be used with bus_find_dev
|
|
* helper function to be used with bus_find_dev
|
|
* matches for the card device with the given id
|
|
* matches for the card device with the given id
|
|
@@ -1014,8 +1067,8 @@ static void ap_scan_bus(struct work_struct *unused)
|
|
struct ap_card *ac;
|
|
struct ap_card *ac;
|
|
struct device *dev;
|
|
struct device *dev;
|
|
ap_qid_t qid;
|
|
ap_qid_t qid;
|
|
- int depth = 0, type = 0;
|
|
|
|
- unsigned int functions = 0;
|
|
|
|
|
|
+ int comp_type, depth = 0, type = 0;
|
|
|
|
+ unsigned int func = 0;
|
|
int rc, id, dom, borked, domains, defdomdevs = 0;
|
|
int rc, id, dom, borked, domains, defdomdevs = 0;
|
|
|
|
|
|
AP_DBF(DBF_DEBUG, "ap_scan_bus running\n");
|
|
AP_DBF(DBF_DEBUG, "ap_scan_bus running\n");
|
|
@@ -1066,12 +1119,12 @@ static void ap_scan_bus(struct work_struct *unused)
|
|
}
|
|
}
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- rc = ap_query_queue(qid, &depth, &type, &functions);
|
|
|
|
|
|
+ rc = ap_query_queue(qid, &depth, &type, &func);
|
|
if (dev) {
|
|
if (dev) {
|
|
spin_lock_bh(&aq->lock);
|
|
spin_lock_bh(&aq->lock);
|
|
if (rc == -ENODEV ||
|
|
if (rc == -ENODEV ||
|
|
/* adapter reconfiguration */
|
|
/* adapter reconfiguration */
|
|
- (ac && ac->functions != functions))
|
|
|
|
|
|
+ (ac && ac->functions != func))
|
|
aq->state = AP_STATE_BORKED;
|
|
aq->state = AP_STATE_BORKED;
|
|
borked = aq->state == AP_STATE_BORKED;
|
|
borked = aq->state == AP_STATE_BORKED;
|
|
spin_unlock_bh(&aq->lock);
|
|
spin_unlock_bh(&aq->lock);
|
|
@@ -1087,11 +1140,14 @@ static void ap_scan_bus(struct work_struct *unused)
|
|
}
|
|
}
|
|
if (rc)
|
|
if (rc)
|
|
continue;
|
|
continue;
|
|
- /* new queue device needed */
|
|
|
|
|
|
+ /* a new queue device is needed, check out comp type */
|
|
|
|
+ comp_type = ap_get_compatible_type(qid, type, func);
|
|
|
|
+ if (!comp_type)
|
|
|
|
+ continue;
|
|
|
|
+ /* maybe a card device needs to be created first */
|
|
if (!ac) {
|
|
if (!ac) {
|
|
- /* but first create the card device */
|
|
|
|
- ac = ap_card_create(id, depth,
|
|
|
|
- type, functions);
|
|
|
|
|
|
+ ac = ap_card_create(id, depth, type,
|
|
|
|
+ comp_type, func);
|
|
if (!ac)
|
|
if (!ac)
|
|
continue;
|
|
continue;
|
|
ac->ap_dev.device.bus = &ap_bus_type;
|
|
ac->ap_dev.device.bus = &ap_bus_type;
|
|
@@ -1109,7 +1165,7 @@ static void ap_scan_bus(struct work_struct *unused)
|
|
get_device(&ac->ap_dev.device);
|
|
get_device(&ac->ap_dev.device);
|
|
}
|
|
}
|
|
/* now create the new queue device */
|
|
/* now create the new queue device */
|
|
- aq = ap_queue_create(qid, type);
|
|
|
|
|
|
+ aq = ap_queue_create(qid, comp_type);
|
|
if (!aq)
|
|
if (!aq)
|
|
continue;
|
|
continue;
|
|
aq->card = ac;
|
|
aq->card = ac;
|