Skip to content

Commit 1da74b1

Browse files
Frank Blaschkadavem330
authored andcommitted
qeth: add OSA concurrent hardware trap
This patch improves FFDC (first failure data capture) by requesting a hardware trace in case the device driver, the hardware or a user detects an error. Signed-off-by: Frank Blaschka <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c5e631a commit 1da74b1

File tree

6 files changed

+268
-37
lines changed

6 files changed

+268
-37
lines changed

drivers/s390/net/qeth_core.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,8 @@ struct qeth_card_info {
631631
__u32 csum_mask;
632632
__u32 tx_csum_mask;
633633
enum qeth_ipa_promisc_modes promisc_mode;
634+
__u32 diagass_support;
635+
__u32 hwtrap;
634636
};
635637

636638
struct qeth_card_options {
@@ -752,6 +754,14 @@ struct qeth_card_list_struct {
752754
rwlock_t rwlock;
753755
};
754756

757+
struct qeth_trap_id {
758+
__u16 lparnr;
759+
char vmname[8];
760+
__u8 chpid;
761+
__u8 ssid;
762+
__u16 devno;
763+
} __packed;
764+
755765
/*some helper functions*/
756766
#define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "")
757767

@@ -786,6 +796,12 @@ static inline void qeth_put_buffer_pool_entry(struct qeth_card *card,
786796
list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list);
787797
}
788798

799+
static inline int qeth_is_diagass_supported(struct qeth_card *card,
800+
enum qeth_diags_cmds cmd)
801+
{
802+
return card->info.diagass_support & (__u32)cmd;
803+
}
804+
789805
extern struct ccwgroup_driver qeth_l2_ccwgroup_driver;
790806
extern struct ccwgroup_driver qeth_l3_ccwgroup_driver;
791807
const char *qeth_get_cardname_short(struct qeth_card *);
@@ -871,6 +887,8 @@ void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
871887
int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
872888
int qeth_set_access_ctrl_online(struct qeth_card *card);
873889
int qeth_hdr_chk_and_bounce(struct sk_buff *, int);
890+
int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
891+
int qeth_query_ipassists(struct qeth_card *, enum qeth_prot_versions prot);
874892

875893
/* exports for OSN */
876894
int qeth_osn_assist(struct net_device *, void *, int);

drivers/s390/net/qeth_core_main.c

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include <asm/ebcdic.h>
2626
#include <asm/io.h>
27+
#include <asm/sysinfo.h>
2728

2829
#include "qeth_core.h"
2930

@@ -349,6 +350,8 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
349350
card->info.chpid);
350351
netif_carrier_on(card->dev);
351352
card->lan_online = 1;
353+
if (card->info.hwtrap)
354+
card->info.hwtrap = 2;
352355
qeth_schedule_recovery(card);
353356
return NULL;
354357
case IPA_CMD_MODCCID:
@@ -2573,6 +2576,142 @@ int qeth_query_setadapterparms(struct qeth_card *card)
25732576
}
25742577
EXPORT_SYMBOL_GPL(qeth_query_setadapterparms);
25752578

2579+
static int qeth_query_ipassists_cb(struct qeth_card *card,
2580+
struct qeth_reply *reply, unsigned long data)
2581+
{
2582+
struct qeth_ipa_cmd *cmd;
2583+
2584+
QETH_DBF_TEXT(SETUP, 2, "qipasscb");
2585+
2586+
cmd = (struct qeth_ipa_cmd *) data;
2587+
if (cmd->hdr.prot_version == QETH_PROT_IPV4) {
2588+
card->options.ipa4.supported_funcs = cmd->hdr.ipa_supported;
2589+
card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled;
2590+
} else {
2591+
card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported;
2592+
card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
2593+
}
2594+
QETH_DBF_TEXT(SETUP, 2, "suppenbl");
2595+
QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_supported);
2596+
QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_enabled);
2597+
return 0;
2598+
}
2599+
2600+
int qeth_query_ipassists(struct qeth_card *card, enum qeth_prot_versions prot)
2601+
{
2602+
int rc;
2603+
struct qeth_cmd_buffer *iob;
2604+
2605+
QETH_DBF_TEXT_(SETUP, 2, "qipassi%i", prot);
2606+
iob = qeth_get_ipacmd_buffer(card, IPA_CMD_QIPASSIST, prot);
2607+
rc = qeth_send_ipa_cmd(card, iob, qeth_query_ipassists_cb, NULL);
2608+
return rc;
2609+
}
2610+
EXPORT_SYMBOL_GPL(qeth_query_ipassists);
2611+
2612+
static int qeth_query_setdiagass_cb(struct qeth_card *card,
2613+
struct qeth_reply *reply, unsigned long data)
2614+
{
2615+
struct qeth_ipa_cmd *cmd;
2616+
__u16 rc;
2617+
2618+
cmd = (struct qeth_ipa_cmd *)data;
2619+
rc = cmd->hdr.return_code;
2620+
if (rc)
2621+
QETH_CARD_TEXT_(card, 2, "diagq:%x", rc);
2622+
else
2623+
card->info.diagass_support = cmd->data.diagass.ext;
2624+
return 0;
2625+
}
2626+
2627+
static int qeth_query_setdiagass(struct qeth_card *card)
2628+
{
2629+
struct qeth_cmd_buffer *iob;
2630+
struct qeth_ipa_cmd *cmd;
2631+
2632+
QETH_DBF_TEXT(SETUP, 2, "qdiagass");
2633+
iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
2634+
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
2635+
cmd->data.diagass.subcmd_len = 16;
2636+
cmd->data.diagass.subcmd = QETH_DIAGS_CMD_QUERY;
2637+
return qeth_send_ipa_cmd(card, iob, qeth_query_setdiagass_cb, NULL);
2638+
}
2639+
2640+
static void qeth_get_trap_id(struct qeth_card *card, struct qeth_trap_id *tid)
2641+
{
2642+
unsigned long info = get_zeroed_page(GFP_KERNEL);
2643+
struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info;
2644+
struct sysinfo_3_2_2 *info322 = (struct sysinfo_3_2_2 *)info;
2645+
struct ccw_dev_id ccwid;
2646+
int level, rc;
2647+
2648+
tid->chpid = card->info.chpid;
2649+
ccw_device_get_id(CARD_RDEV(card), &ccwid);
2650+
tid->ssid = ccwid.ssid;
2651+
tid->devno = ccwid.devno;
2652+
if (!info)
2653+
return;
2654+
2655+
rc = stsi(NULL, 0, 0, 0);
2656+
if (rc == -ENOSYS)
2657+
level = rc;
2658+
else
2659+
level = (((unsigned int) rc) >> 28);
2660+
2661+
if ((level >= 2) && (stsi(info222, 2, 2, 2) != -ENOSYS))
2662+
tid->lparnr = info222->lpar_number;
2663+
2664+
if ((level >= 3) && (stsi(info322, 3, 2, 2) != -ENOSYS)) {
2665+
EBCASC(info322->vm[0].name, sizeof(info322->vm[0].name));
2666+
memcpy(tid->vmname, info322->vm[0].name, sizeof(tid->vmname));
2667+
}
2668+
free_page(info);
2669+
return;
2670+
}
2671+
2672+
static int qeth_hw_trap_cb(struct qeth_card *card,
2673+
struct qeth_reply *reply, unsigned long data)
2674+
{
2675+
struct qeth_ipa_cmd *cmd;
2676+
__u16 rc;
2677+
2678+
cmd = (struct qeth_ipa_cmd *)data;
2679+
rc = cmd->hdr.return_code;
2680+
if (rc)
2681+
QETH_CARD_TEXT_(card, 2, "trapc:%x", rc);
2682+
return 0;
2683+
}
2684+
2685+
int qeth_hw_trap(struct qeth_card *card, enum qeth_diags_trap_action action)
2686+
{
2687+
struct qeth_cmd_buffer *iob;
2688+
struct qeth_ipa_cmd *cmd;
2689+
2690+
QETH_DBF_TEXT(SETUP, 2, "diagtrap");
2691+
iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
2692+
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
2693+
cmd->data.diagass.subcmd_len = 80;
2694+
cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRAP;
2695+
cmd->data.diagass.type = 1;
2696+
cmd->data.diagass.action = action;
2697+
switch (action) {
2698+
case QETH_DIAGS_TRAP_ARM:
2699+
cmd->data.diagass.options = 0x0003;
2700+
cmd->data.diagass.ext = 0x00010000 +
2701+
sizeof(struct qeth_trap_id);
2702+
qeth_get_trap_id(card,
2703+
(struct qeth_trap_id *)cmd->data.diagass.cdata);
2704+
break;
2705+
case QETH_DIAGS_TRAP_DISARM:
2706+
cmd->data.diagass.options = 0x0001;
2707+
break;
2708+
case QETH_DIAGS_TRAP_CAPTURE:
2709+
break;
2710+
}
2711+
return qeth_send_ipa_cmd(card, iob, qeth_hw_trap_cb, NULL);
2712+
}
2713+
EXPORT_SYMBOL_GPL(qeth_hw_trap);
2714+
25762715
int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf,
25772716
unsigned int qdio_error, const char *dbftext)
25782717
{
@@ -3983,6 +4122,15 @@ int qeth_core_hardsetup_card(struct qeth_card *card)
39834122
QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
39844123
goto out;
39854124
}
4125+
4126+
card->options.ipa4.supported_funcs = 0;
4127+
card->options.adp.supported_funcs = 0;
4128+
card->info.diagass_support = 0;
4129+
qeth_query_ipassists(card, QETH_PROT_IPV4);
4130+
if (qeth_is_supported(card, IPA_SETADAPTERPARMS))
4131+
qeth_query_setadapterparms(card);
4132+
if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST))
4133+
qeth_query_setdiagass(card);
39864134
return 0;
39874135
out:
39884136
dev_warn(&card->gdev->dev, "The qeth device driver failed to recover "

drivers/s390/net/qeth_core_mpc.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,12 @@ enum qeth_diags_trace_cmds {
448448
QETH_DIAGS_CMD_TRACE_QUERY = 0x0010,
449449
};
450450

451+
enum qeth_diags_trap_action {
452+
QETH_DIAGS_TRAP_ARM = 0x01,
453+
QETH_DIAGS_TRAP_DISARM = 0x02,
454+
QETH_DIAGS_TRAP_CAPTURE = 0x04,
455+
};
456+
451457
struct qeth_ipacmd_diagass {
452458
__u32 host_tod2;
453459
__u32:32;
@@ -457,7 +463,8 @@ struct qeth_ipacmd_diagass {
457463
__u8 type;
458464
__u8 action;
459465
__u16 options;
460-
__u32:32;
466+
__u32 ext;
467+
__u8 cdata[64];
461468
} __attribute__ ((packed));
462469

463470
/* Header for each IPA command */

drivers/s390/net/qeth_core_sys.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,66 @@ static ssize_t qeth_dev_isolation_store(struct device *dev,
530530
static DEVICE_ATTR(isolation, 0644, qeth_dev_isolation_show,
531531
qeth_dev_isolation_store);
532532

533+
static ssize_t qeth_hw_trap_show(struct device *dev,
534+
struct device_attribute *attr, char *buf)
535+
{
536+
struct qeth_card *card = dev_get_drvdata(dev);
537+
538+
if (!card)
539+
return -EINVAL;
540+
if (card->info.hwtrap)
541+
return snprintf(buf, 5, "arm\n");
542+
else
543+
return snprintf(buf, 8, "disarm\n");
544+
}
545+
546+
static ssize_t qeth_hw_trap_store(struct device *dev,
547+
struct device_attribute *attr, const char *buf, size_t count)
548+
{
549+
struct qeth_card *card = dev_get_drvdata(dev);
550+
int rc = 0;
551+
char *tmp, *curtoken;
552+
int state = 0;
553+
curtoken = (char *)buf;
554+
555+
if (!card)
556+
return -EINVAL;
557+
558+
mutex_lock(&card->conf_mutex);
559+
if (card->state == CARD_STATE_SOFTSETUP || card->state == CARD_STATE_UP)
560+
state = 1;
561+
tmp = strsep(&curtoken, "\n");
562+
563+
if (!strcmp(tmp, "arm") && !card->info.hwtrap) {
564+
if (state) {
565+
if (qeth_is_diagass_supported(card,
566+
QETH_DIAGS_CMD_TRAP)) {
567+
rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM);
568+
if (!rc)
569+
card->info.hwtrap = 1;
570+
} else
571+
rc = -EINVAL;
572+
} else
573+
card->info.hwtrap = 1;
574+
} else if (!strcmp(tmp, "disarm") && card->info.hwtrap) {
575+
if (state) {
576+
rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
577+
if (!rc)
578+
card->info.hwtrap = 0;
579+
} else
580+
card->info.hwtrap = 0;
581+
} else if (!strcmp(tmp, "trap") && state && card->info.hwtrap)
582+
rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_CAPTURE);
583+
else
584+
rc = -EINVAL;
585+
586+
mutex_unlock(&card->conf_mutex);
587+
return rc ? rc : count;
588+
}
589+
590+
static DEVICE_ATTR(hw_trap, 0644, qeth_hw_trap_show,
591+
qeth_hw_trap_store);
592+
533593
static ssize_t qeth_dev_blkt_show(char *buf, struct qeth_card *card, int value)
534594
{
535595

@@ -653,6 +713,7 @@ static struct attribute *qeth_device_attrs[] = {
653713
&dev_attr_performance_stats.attr,
654714
&dev_attr_layer2.attr,
655715
&dev_attr_isolation.attr,
716+
&dev_attr_hw_trap.attr,
656717
NULL,
657718
};
658719

drivers/s390/net/qeth_l2_main.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,7 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
876876
INIT_LIST_HEAD(&card->vid_list);
877877
INIT_LIST_HEAD(&card->mc_list);
878878
card->options.layer2 = 1;
879+
card->info.hwtrap = 0;
879880
card->discipline.start_poll = qeth_qdio_start_poll;
880881
card->discipline.input_handler = (qdio_handler_t *)
881882
qeth_qdio_input_handler;
@@ -994,6 +995,13 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
994995
if (card->info.type != QETH_CARD_TYPE_OSN)
995996
qeth_l2_send_setmac(card, &card->dev->dev_addr[0]);
996997

998+
if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
999+
if (card->info.hwtrap &&
1000+
qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM))
1001+
card->info.hwtrap = 0;
1002+
} else
1003+
card->info.hwtrap = 0;
1004+
9971005
card->state = CARD_STATE_HARDSETUP;
9981006
memset(&card->rx, 0, sizeof(struct qeth_rx));
9991007
qeth_print_status_message(card);
@@ -1092,6 +1100,10 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
10921100
if (card->dev && netif_carrier_ok(card->dev))
10931101
netif_carrier_off(card->dev);
10941102
recover_flag = card->state;
1103+
if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) {
1104+
qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
1105+
card->info.hwtrap = 1;
1106+
}
10951107
qeth_l2_stop_card(card, recovery_mode);
10961108
rc = ccw_device_set_offline(CARD_DDEV(card));
10971109
rc2 = ccw_device_set_offline(CARD_WDEV(card));
@@ -1157,6 +1169,8 @@ static void __exit qeth_l2_exit(void)
11571169
static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
11581170
{
11591171
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
1172+
if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap)
1173+
qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
11601174
qeth_qdio_clear_card(card, 0);
11611175
qeth_clear_qdio_buffers(card);
11621176
}
@@ -1172,6 +1186,8 @@ static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
11721186
if (gdev->state == CCWGROUP_OFFLINE)
11731187
return 0;
11741188
if (card->state == CARD_STATE_UP) {
1189+
if (card->info.hwtrap)
1190+
qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
11751191
__qeth_l2_set_offline(card->gdev, 1);
11761192
} else
11771193
__qeth_l2_set_offline(card->gdev, 0);

0 commit comments

Comments
 (0)