|
@@ -68,6 +68,27 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
|
|
|
enum qeth_qdio_buffer_states newbufstate);
|
|
|
static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
|
|
|
|
|
|
+static struct workqueue_struct *qeth_wq;
|
|
|
+
|
|
|
+static void qeth_close_dev_handler(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct qeth_card *card;
|
|
|
+
|
|
|
+ card = container_of(work, struct qeth_card, close_dev_work);
|
|
|
+ QETH_CARD_TEXT(card, 2, "cldevhdl");
|
|
|
+ rtnl_lock();
|
|
|
+ dev_close(card->dev);
|
|
|
+ rtnl_unlock();
|
|
|
+ ccwgroup_set_offline(card->gdev);
|
|
|
+}
|
|
|
+
|
|
|
+void qeth_close_dev(struct qeth_card *card)
|
|
|
+{
|
|
|
+ QETH_CARD_TEXT(card, 2, "cldevsubm");
|
|
|
+ queue_work(qeth_wq, &card->close_dev_work);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(qeth_close_dev);
|
|
|
+
|
|
|
static inline const char *qeth_get_cardname(struct qeth_card *card)
|
|
|
{
|
|
|
if (card->info.guestlan) {
|
|
@@ -542,11 +563,23 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
|
|
|
} else {
|
|
|
switch (cmd->hdr.command) {
|
|
|
case IPA_CMD_STOPLAN:
|
|
|
- dev_warn(&card->gdev->dev,
|
|
|
+ if (cmd->hdr.return_code ==
|
|
|
+ IPA_RC_VEPA_TO_VEB_TRANSITION) {
|
|
|
+ dev_err(&card->gdev->dev,
|
|
|
+ "Interface %s is down because the "
|
|
|
+ "adjacent port is no longer in "
|
|
|
+ "reflective relay mode\n",
|
|
|
+ QETH_CARD_IFNAME(card));
|
|
|
+ qeth_close_dev(card);
|
|
|
+ } else {
|
|
|
+ dev_warn(&card->gdev->dev,
|
|
|
"The link for interface %s on CHPID"
|
|
|
" 0x%X failed\n",
|
|
|
QETH_CARD_IFNAME(card),
|
|
|
card->info.chpid);
|
|
|
+ qeth_issue_ipa_msg(cmd,
|
|
|
+ cmd->hdr.return_code, card);
|
|
|
+ }
|
|
|
card->lan_online = 0;
|
|
|
if (card->dev && netif_carrier_ok(card->dev))
|
|
|
netif_carrier_off(card->dev);
|
|
@@ -1416,6 +1449,7 @@ static int qeth_setup_card(struct qeth_card *card)
|
|
|
/* init QDIO stuff */
|
|
|
qeth_init_qdio_info(card);
|
|
|
INIT_DELAYED_WORK(&card->buffer_reclaim_work, qeth_buffer_reclaim_work);
|
|
|
+ INIT_WORK(&card->close_dev_work, qeth_close_dev_handler);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -4057,6 +4091,7 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
|
|
|
{
|
|
|
struct qeth_ipa_cmd *cmd;
|
|
|
struct qeth_set_access_ctrl *access_ctrl_req;
|
|
|
+ int fallback = *(int *)reply->param;
|
|
|
|
|
|
QETH_CARD_TEXT(card, 4, "setaccb");
|
|
|
|
|
@@ -4066,12 +4101,14 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
|
|
|
QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
|
|
|
QETH_DBF_TEXT_(SETUP, 2, "rc=%d",
|
|
|
cmd->data.setadapterparms.hdr.return_code);
|
|
|
+ if (cmd->data.setadapterparms.hdr.return_code !=
|
|
|
+ SET_ACCESS_CTRL_RC_SUCCESS)
|
|
|
+ QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n",
|
|
|
+ card->gdev->dev.kobj.name,
|
|
|
+ access_ctrl_req->subcmd_code,
|
|
|
+ cmd->data.setadapterparms.hdr.return_code);
|
|
|
switch (cmd->data.setadapterparms.hdr.return_code) {
|
|
|
case SET_ACCESS_CTRL_RC_SUCCESS:
|
|
|
- case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED:
|
|
|
- case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED:
|
|
|
- {
|
|
|
- card->options.isolation = access_ctrl_req->subcmd_code;
|
|
|
if (card->options.isolation == ISOLATION_MODE_NONE) {
|
|
|
dev_info(&card->gdev->dev,
|
|
|
"QDIO data connection isolation is deactivated\n");
|
|
@@ -4079,72 +4116,64 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
|
|
|
dev_info(&card->gdev->dev,
|
|
|
"QDIO data connection isolation is activated\n");
|
|
|
}
|
|
|
- QETH_DBF_MESSAGE(3, "OK:SET_ACCESS_CTRL(%s, %d)==%d\n",
|
|
|
- card->gdev->dev.kobj.name,
|
|
|
- access_ctrl_req->subcmd_code,
|
|
|
- cmd->data.setadapterparms.hdr.return_code);
|
|
|
break;
|
|
|
- }
|
|
|
+ case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED:
|
|
|
+ QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already "
|
|
|
+ "deactivated\n", dev_name(&card->gdev->dev));
|
|
|
+ if (fallback)
|
|
|
+ card->options.isolation = card->options.prev_isolation;
|
|
|
+ break;
|
|
|
+ case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED:
|
|
|
+ QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already"
|
|
|
+ " activated\n", dev_name(&card->gdev->dev));
|
|
|
+ if (fallback)
|
|
|
+ card->options.isolation = card->options.prev_isolation;
|
|
|
+ break;
|
|
|
case SET_ACCESS_CTRL_RC_NOT_SUPPORTED:
|
|
|
- {
|
|
|
- QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n",
|
|
|
- card->gdev->dev.kobj.name,
|
|
|
- access_ctrl_req->subcmd_code,
|
|
|
- cmd->data.setadapterparms.hdr.return_code);
|
|
|
dev_err(&card->gdev->dev, "Adapter does not "
|
|
|
"support QDIO data connection isolation\n");
|
|
|
-
|
|
|
- /* ensure isolation mode is "none" */
|
|
|
- card->options.isolation = ISOLATION_MODE_NONE;
|
|
|
break;
|
|
|
- }
|
|
|
case SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER:
|
|
|
- {
|
|
|
- QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n",
|
|
|
- card->gdev->dev.kobj.name,
|
|
|
- access_ctrl_req->subcmd_code,
|
|
|
- cmd->data.setadapterparms.hdr.return_code);
|
|
|
dev_err(&card->gdev->dev,
|
|
|
"Adapter is dedicated. "
|
|
|
"QDIO data connection isolation not supported\n");
|
|
|
-
|
|
|
- /* ensure isolation mode is "none" */
|
|
|
- card->options.isolation = ISOLATION_MODE_NONE;
|
|
|
+ if (fallback)
|
|
|
+ card->options.isolation = card->options.prev_isolation;
|
|
|
break;
|
|
|
- }
|
|
|
case SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF:
|
|
|
- {
|
|
|
- QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n",
|
|
|
- card->gdev->dev.kobj.name,
|
|
|
- access_ctrl_req->subcmd_code,
|
|
|
- cmd->data.setadapterparms.hdr.return_code);
|
|
|
dev_err(&card->gdev->dev,
|
|
|
"TSO does not permit QDIO data connection isolation\n");
|
|
|
-
|
|
|
- /* ensure isolation mode is "none" */
|
|
|
- card->options.isolation = ISOLATION_MODE_NONE;
|
|
|
+ if (fallback)
|
|
|
+ card->options.isolation = card->options.prev_isolation;
|
|
|
+ break;
|
|
|
+ case SET_ACCESS_CTRL_RC_REFLREL_UNSUPPORTED:
|
|
|
+ dev_err(&card->gdev->dev, "The adjacent switch port does not "
|
|
|
+ "support reflective relay mode\n");
|
|
|
+ if (fallback)
|
|
|
+ card->options.isolation = card->options.prev_isolation;
|
|
|
+ break;
|
|
|
+ case SET_ACCESS_CTRL_RC_REFLREL_FAILED:
|
|
|
+ dev_err(&card->gdev->dev, "The reflective relay mode cannot be "
|
|
|
+ "enabled at the adjacent switch port");
|
|
|
+ if (fallback)
|
|
|
+ card->options.isolation = card->options.prev_isolation;
|
|
|
+ break;
|
|
|
+ case SET_ACCESS_CTRL_RC_REFLREL_DEACT_FAILED:
|
|
|
+ dev_warn(&card->gdev->dev, "Turning off reflective relay mode "
|
|
|
+ "at the adjacent switch failed\n");
|
|
|
break;
|
|
|
- }
|
|
|
default:
|
|
|
- {
|
|
|
/* this should never happen */
|
|
|
- QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d"
|
|
|
- "==UNKNOWN\n",
|
|
|
- card->gdev->dev.kobj.name,
|
|
|
- access_ctrl_req->subcmd_code,
|
|
|
- cmd->data.setadapterparms.hdr.return_code);
|
|
|
-
|
|
|
- /* ensure isolation mode is "none" */
|
|
|
- card->options.isolation = ISOLATION_MODE_NONE;
|
|
|
+ if (fallback)
|
|
|
+ card->options.isolation = card->options.prev_isolation;
|
|
|
break;
|
|
|
}
|
|
|
- }
|
|
|
qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
|
|
|
- enum qeth_ipa_isolation_modes isolation)
|
|
|
+ enum qeth_ipa_isolation_modes isolation, int fallback)
|
|
|
{
|
|
|
int rc;
|
|
|
struct qeth_cmd_buffer *iob;
|
|
@@ -4164,12 +4193,12 @@ static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
|
|
|
access_ctrl_req->subcmd_code = isolation;
|
|
|
|
|
|
rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_set_access_ctrl_cb,
|
|
|
- NULL);
|
|
|
+ &fallback);
|
|
|
QETH_DBF_TEXT_(SETUP, 2, "rc=%d", rc);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-int qeth_set_access_ctrl_online(struct qeth_card *card)
|
|
|
+int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback)
|
|
|
{
|
|
|
int rc = 0;
|
|
|
|
|
@@ -4179,12 +4208,13 @@ int qeth_set_access_ctrl_online(struct qeth_card *card)
|
|
|
card->info.type == QETH_CARD_TYPE_OSX) &&
|
|
|
qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) {
|
|
|
rc = qeth_setadpparms_set_access_ctrl(card,
|
|
|
- card->options.isolation);
|
|
|
+ card->options.isolation, fallback);
|
|
|
if (rc) {
|
|
|
QETH_DBF_MESSAGE(3,
|
|
|
"IPA(SET_ACCESS_CTRL,%s,%d) sent failed\n",
|
|
|
card->gdev->dev.kobj.name,
|
|
|
rc);
|
|
|
+ rc = -EOPNOTSUPP;
|
|
|
}
|
|
|
} else if (card->options.isolation != ISOLATION_MODE_NONE) {
|
|
|
card->options.isolation = ISOLATION_MODE_NONE;
|
|
@@ -5552,6 +5582,8 @@ static int __init qeth_core_init(void)
|
|
|
rwlock_init(&qeth_core_card_list.rwlock);
|
|
|
mutex_init(&qeth_mod_mutex);
|
|
|
|
|
|
+ qeth_wq = create_singlethread_workqueue("qeth_wq");
|
|
|
+
|
|
|
rc = qeth_register_dbf_views();
|
|
|
if (rc)
|
|
|
goto out_err;
|
|
@@ -5598,6 +5630,7 @@ out_err:
|
|
|
|
|
|
static void __exit qeth_core_exit(void)
|
|
|
{
|
|
|
+ destroy_workqueue(qeth_wq);
|
|
|
ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver);
|
|
|
ccw_driver_unregister(&qeth_ccw_driver);
|
|
|
kmem_cache_destroy(qeth_qdio_outbuf_cache);
|