in crypto/ap_bus.c [1647:1793]
static inline void ap_scan_adapter(int ap)
{
bool decfg;
ap_qid_t qid;
unsigned int func;
struct device *dev;
struct ap_card *ac;
int rc, dom, depth, type, comp_type, ml;
/* Is there currently a card device for this adapter ? */
dev = bus_find_device(&ap_bus_type, NULL,
(void *)(long) ap,
__match_card_device_with_id);
ac = dev ? to_ap_card(dev) : NULL;
/* Adapter not in configuration ? */
if (!ap_test_config_card_id(ap)) {
if (ac) {
AP_DBF_INFO("%s(%d) ap not in config any more, rm card and queue devs\n",
__func__, ap);
ap_scan_rm_card_dev_and_queue_devs(ac);
put_device(dev);
}
return;
}
/*
* Adapter ap is valid in the current configuration. So do some checks:
* If no card device exists, build one. If a card device exists, check
* for type and functions changed. For all this we need to find a valid
* APQN first.
*/
for (dom = 0; dom <= ap_max_domain_id; dom++)
if (ap_test_config_usage_domain(dom)) {
qid = AP_MKQID(ap, dom);
if (ap_queue_info(qid, &type, &func,
&depth, &ml, &decfg))
break;
}
if (dom > ap_max_domain_id) {
/* Could not find a valid APQN for this adapter */
if (ac) {
AP_DBF_INFO("%s(%d) no type info (no APQN found), rm card and queue devs\n",
__func__, ap);
ap_scan_rm_card_dev_and_queue_devs(ac);
put_device(dev);
} else {
AP_DBF_DBG("%s(%d) no type info (no APQN found), ignored\n",
__func__, ap);
}
return;
}
if (!type) {
/* No apdater type info available, an unusable adapter */
if (ac) {
AP_DBF_INFO("%s(%d) no valid type (0) info, rm card and queue devs\n",
__func__, ap);
ap_scan_rm_card_dev_and_queue_devs(ac);
put_device(dev);
} else {
AP_DBF_DBG("%s(%d) no valid type (0) info, ignored\n",
__func__, ap);
}
return;
}
if (ac) {
/* Check APQN against existing card device for changes */
if (ac->raw_hwtype != type) {
AP_DBF_INFO("%s(%d) hwtype %d changed, rm card and queue devs\n",
__func__, ap, type);
ap_scan_rm_card_dev_and_queue_devs(ac);
put_device(dev);
ac = NULL;
} else if (ac->functions != func) {
AP_DBF_INFO("%s(%d) functions 0x%08x changed, rm card and queue devs\n",
__func__, ap, type);
ap_scan_rm_card_dev_and_queue_devs(ac);
put_device(dev);
ac = NULL;
} else {
if (decfg && ac->config) {
ac->config = false;
AP_DBF_INFO("%s(%d) card dev config off\n",
__func__, ap);
ap_send_config_uevent(&ac->ap_dev, ac->config);
}
if (!decfg && !ac->config) {
ac->config = true;
AP_DBF_INFO("%s(%d) card dev config on\n",
__func__, ap);
ap_send_config_uevent(&ac->ap_dev, ac->config);
}
}
}
if (!ac) {
/* Build a new card device */
comp_type = ap_get_compatible_type(qid, type, func);
if (!comp_type) {
AP_DBF_WARN("%s(%d) type %d, can't get compatibility type\n",
__func__, ap, type);
return;
}
ac = ap_card_create(ap, depth, type, comp_type, func, ml);
if (!ac) {
AP_DBF_WARN("%s(%d) ap_card_create() failed\n",
__func__, ap);
return;
}
ac->config = !decfg;
dev = &ac->ap_dev.device;
dev->bus = &ap_bus_type;
dev->parent = ap_root_device;
dev_set_name(dev, "card%02x", ap);
/* maybe enlarge ap_max_msg_size to support this card */
if (ac->maxmsgsize > atomic_read(&ap_max_msg_size)) {
atomic_set(&ap_max_msg_size, ac->maxmsgsize);
AP_DBF_INFO("%s(%d) ap_max_msg_size update to %d byte\n",
__func__, ap,
atomic_read(&ap_max_msg_size));
}
/* Register the new card device with AP bus */
rc = device_register(dev);
if (rc) {
AP_DBF_WARN("%s(%d) device_register() failed\n",
__func__, ap);
put_device(dev);
return;
}
/* get it and thus adjust reference counter */
get_device(dev);
if (decfg)
AP_DBF_INFO("%s(%d) new (decfg) card dev type=%d func=0x%08x created\n",
__func__, ap, type, func);
else
AP_DBF_INFO("%s(%d) new card dev type=%d func=0x%08x created\n",
__func__, ap, type, func);
}
/* Verify the domains and the queue devices for this card */
ap_scan_domains(ac);
/* release the card device */
put_device(&ac->ap_dev.device);
}