From f3aa3136d9c15ff693198eb34701a74bb0b6b969 Mon Sep 17 00:00:00 2001 From: Sachin Sant Date: Fri, 26 Nov 2010 02:41:17 +0000 Subject: qeth lcs: convert mc rwlock to RCU Commit 1d7138de878d1d4210727c1200193e69596f93b3 igmp: RCU conversion of in_dev->mc_list converted rwlock to RCU. Update the s390 network drivers(qeth & lcs) code to adapt to this change. V2 : Changes based on suggestions given by Eric Dumazet Signed-off-by: Sachin Sant Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- drivers/s390/net/lcs.c | 10 ++++++---- drivers/s390/net/qeth_l3_main.c | 11 ++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 0f19d540b655..c9f13b9ea339 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1188,7 +1188,8 @@ lcs_remove_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) spin_lock_irqsave(&card->ipm_lock, flags); list_for_each(l, &card->ipm_list) { ipm = list_entry(l, struct lcs_ipm_list, list); - for (im4 = in4_dev->mc_list; im4 != NULL; im4 = im4->next) { + for (im4 = rcu_dereference(in4_dev->mc_list); + im4 != NULL; im4 = rcu_dereference(im4->next_rcu)) { lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev); if ( (ipm->ipm.ip_addr == im4->multiaddr) && (memcmp(buf, &ipm->ipm.mac_addr, @@ -1233,7 +1234,8 @@ lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) unsigned long flags; LCS_DBF_TEXT(4, trace, "setmclst"); - for (im4 = in4_dev->mc_list; im4; im4 = im4->next) { + for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL; + im4 = rcu_dereference(im4->next_rcu)) { lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev); ipm = lcs_check_addr_entry(card, im4, buf); if (ipm != NULL) @@ -1269,10 +1271,10 @@ lcs_register_mc_addresses(void *data) in4_dev = in_dev_get(card->dev); if (in4_dev == NULL) goto out; - read_lock(&in4_dev->mc_list_lock); + rcu_read_lock(); lcs_remove_mc_addresses(card,in4_dev); lcs_set_mc_addresses(card, in4_dev); - read_unlock(&in4_dev->mc_list_lock); + rcu_read_unlock(); in_dev_put(in4_dev); netif_carrier_off(card->dev); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 74d1401a5d5e..65291db324f5 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1796,7 +1796,8 @@ static void qeth_l3_add_mc(struct qeth_card *card, struct in_device *in4_dev) char buf[MAX_ADDR_LEN]; QETH_CARD_TEXT(card, 4, "addmc"); - for (im4 = in4_dev->mc_list; im4; im4 = im4->next) { + for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL; + im4 = rcu_dereference(im4->next_rcu)) { qeth_l3_get_mac_for_ipm(im4->multiaddr, buf, in4_dev->dev); ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); if (!ipm) @@ -1828,9 +1829,9 @@ static void qeth_l3_add_vlan_mc(struct qeth_card *card) in_dev = in_dev_get(netdev); if (!in_dev) continue; - read_lock(&in_dev->mc_list_lock); + rcu_read_lock(); qeth_l3_add_mc(card, in_dev); - read_unlock(&in_dev->mc_list_lock); + rcu_read_unlock(); in_dev_put(in_dev); } } @@ -1843,10 +1844,10 @@ static void qeth_l3_add_multicast_ipv4(struct qeth_card *card) in4_dev = in_dev_get(card->dev); if (in4_dev == NULL) return; - read_lock(&in4_dev->mc_list_lock); + rcu_read_lock(); qeth_l3_add_mc(card, in4_dev); qeth_l3_add_vlan_mc(card); - read_unlock(&in4_dev->mc_list_lock); + rcu_read_unlock(); in_dev_put(in4_dev); } -- cgit v1.2.3 From cdac082e051136a021f28d0f63c56e916b541253 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 26 Nov 2010 02:41:18 +0000 Subject: drivers/s390/net: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 42fa783a70c8..b5e967cf7e2d 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -372,7 +372,7 @@ static ssize_t qeth_dev_performance_stats_store(struct device *dev, i = simple_strtoul(buf, &tmp, 16); if ((i == 0) || (i == 1)) { if (i == card->options.performance_stats) - goto out;; + goto out; card->options.performance_stats = i; if (i == 0) memset(&card->perf_stats, 0, -- cgit v1.2.3 From 2b6203bb7d85e6a2ca2088b8684f30be70246ddf Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Fri, 26 Nov 2010 02:41:19 +0000 Subject: qeth: enable interface setup if LAN is offline Device initialization of a qeth device contains a STARTLAN step. This step may fail, if cable is not yet plugged in. The qeth device stays in state HARDSETUP until cable is plugged in. This prevents further preparational initialization steps of the qeth device and its network interface. This patch makes sure initialization of qeth device continues, even though cable is not yet plugged in. Once carrier is available, qeth is notified, triggers a recovery which results in a working network interface. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l2_main.c | 11 ++++++----- drivers/s390/net/qeth_l3_main.c | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 847e8797073c..7a7a1b664781 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -849,8 +849,6 @@ static int qeth_l2_open(struct net_device *dev) card->state = CARD_STATE_UP; netif_start_queue(dev); - if (!card->lan_online && netif_carrier_ok(dev)) - netif_carrier_off(dev); if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) { napi_enable(&card->napi); napi_schedule(&card->napi); @@ -1013,13 +1011,14 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) dev_warn(&card->gdev->dev, "The LAN is offline\n"); card->lan_online = 0; - goto out; + goto contin; } rc = -ENODEV; goto out_remove; } else card->lan_online = 1; +contin: if ((card->info.type == QETH_CARD_TYPE_OSD) || (card->info.type == QETH_CARD_TYPE_OSX)) /* configure isolation level */ @@ -1038,7 +1037,10 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) goto out_remove; } card->state = CARD_STATE_SOFTSETUP; - netif_carrier_on(card->dev); + if (card->lan_online) + netif_carrier_on(card->dev); + else + netif_carrier_off(card->dev); qeth_set_allowed_threads(card, 0xffffffff, 0); if (recover_flag == CARD_STATE_RECOVER) { @@ -1055,7 +1057,6 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) } /* let user_space know that device is online */ kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE); -out: mutex_unlock(&card->conf_mutex); mutex_unlock(&card->discipline_mutex); return 0; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 65291db324f5..3ddd5add7984 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3177,8 +3177,6 @@ static int qeth_l3_open(struct net_device *dev) card->state = CARD_STATE_UP; netif_start_queue(dev); - if (!card->lan_online && netif_carrier_ok(dev)) - netif_carrier_off(dev); if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) { napi_enable(&card->napi); napi_schedule(&card->napi); @@ -3450,13 +3448,14 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) dev_warn(&card->gdev->dev, "The LAN is offline\n"); card->lan_online = 0; - goto out; + goto contin; } rc = -ENODEV; goto out_remove; } else card->lan_online = 1; +contin: rc = qeth_l3_setadapter_parms(card); if (rc) QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); @@ -3481,10 +3480,13 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) goto out_remove; } card->state = CARD_STATE_SOFTSETUP; - netif_carrier_on(card->dev); qeth_set_allowed_threads(card, 0xffffffff, 0); qeth_l3_set_ip_addr_list(card); + if (card->lan_online) + netif_carrier_on(card->dev); + else + netif_carrier_off(card->dev); if (recover_flag == CARD_STATE_RECOVER) { if (recovery_mode) qeth_l3_open(card->dev); @@ -3497,7 +3499,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) } /* let user_space know that device is online */ kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE); -out: mutex_unlock(&card->conf_mutex); mutex_unlock(&card->discipline_mutex); return 0; -- cgit v1.2.3 From 8fa9208e305e24978b897d6ea057604444ce77e1 Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Fri, 26 Nov 2010 02:41:20 +0000 Subject: qeth: l3 fix len in tso hdr The tso hdr is longer then the regular l3 hdr. Fix the calculation of the total len by accounting the size of the tso hdr. Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 3ddd5add7984..a1abb37db000 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2939,6 +2939,7 @@ static void qeth_tso_fill_header(struct qeth_card *card, /*fix header to TSO values ...*/ hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO; + hdr->hdr.hdr.l3.length = skb->len - sizeof(struct qeth_hdr_tso); /*set values which are fix for the first approach ...*/ hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso); hdr->ext.imb_hdr_no = 1; -- cgit v1.2.3 From 8d7bfb4a891d606d52e1a99cf7231b4417b935dc Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 1 Dec 2010 10:08:02 +0100 Subject: [S390] css: fix rsid evaluation for 2nd crw Use correct bit positions of rsid field. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index a5050e217150..825951b6b83f 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -635,7 +635,7 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) init_subchannel_id(&mchk_schid); mchk_schid.sch_no = crw0->rsid; if (crw1) - mchk_schid.ssid = (crw1->rsid >> 8) & 3; + mchk_schid.ssid = (crw1->rsid >> 4) & 3; /* * Since we are always presented with IPI in the CRW, we have to -- cgit v1.2.3 From 5bfb2c31487eaff3840e02548e6acf89a048765b Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Wed, 17 Nov 2010 14:23:40 +0100 Subject: [SCSI] zfcp: Fix common FCP request reception The reception of a common FCP request should only be evaluated if the corresponding SCSI request data is available. Therefore put the information under the lock protection and verify the existence before processing. This fixes the following kernel panic. Unable to handle kernel pointer dereference at virtual kernel address 0000000180000000 Oops: 003b [#1] PREEMPT SMP DEBUG_PAGEALLOC CPU: 0 Not tainted 2.6.35.7-45.x.20101007-s390xdefault #1 Process blast (pid: 9711, task: 00000000a3be8e40, ksp: 00000000b221bac0) Krnl PSW : 0704300180000000 0000000000489878 (zfcp_fsf_fcp_handler_common+0x4c/0x3a0) R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3 Krnl GPRS: 00000000b663c1b8 0000000180000000 000000007ab5bdf0 0000000000000000 00000000b0ccd800 0000000000000018 07000000a3be8e78 00000000b5d3e600 000000007ab5bdf0 0000000000000066 00000000b72137f0 00000000b72137f0 0000000000000000 00000000005a8178 00000000bdf37a60 00000000bdf379f0 Krnl Code: 0000000000489866: e3c030000004 lg %r12,0(%r3) 000000000048986c: e310c0000004 lg %r1,0(%r12) 0000000000489872: e31011e00004 lg %r1,480(%r1) >0000000000489878: 581011ec l %r1,492(%r1) 000000000048987c: a774001c brc 7,4898b4 0000000000489880: b91400b1 lgfr %r11,%r1 0000000000489884: 5810405c l %r1,92(%r4) 0000000000489888: 5510d00c cl %r1,12(%r13) Call Trace: ([<000000000010d344>] debug_event_common+0x22c/0x244) [<000000000048a0b4>] zfcp_fsf_fcp_cmnd_handler+0x2c/0x3b4 [<000000000048b5b6>] zfcp_fsf_req_complete+0x1b6/0x9dc [<000000000048bede>] zfcp_fsf_reqid_check+0x102/0x138 [<000000000048e478>] zfcp_qdio_int_resp+0x70/0x110 [<000000000044a1ec>] qdio_kick_handler+0xb0/0x19c [<000000000044c228>] __tiqdio_inbound_processing+0x30c/0xebc [<000000000014a5fc>] tasklet_action+0x1b4/0x1e8 [<000000000014b676>] __do_softirq+0x106/0x1cc [<000000000010d91a>] do_softirq+0xe6/0xec [<000000000014b0c8>] irq_exit+0xd4/0xd8 [<00000000004307ec>] do_IRQ+0x7c0/0xf54 [<0000000000114d28>] io_return+0x0/0x16 [<000000000055fef0>] sub_preempt_count+0x50/0xe4 ([<00000000b1f873c0>] 0xb1f873c0) [<000000000055e25a>] _raw_spin_unlock+0x46/0x74 [<0000000000241c40>] __d_lookup+0x288/0x2c8 [<000000000023502c>] do_lookup+0x7c/0x25c [<0000000000237fa8>] link_path_walk+0x5e4/0xe2c [<0000000000238a00>] path_walk+0x98/0x148 [<0000000000238c98>] do_path_lookup+0x74/0xc0 [<000000000023989c>] user_path_at+0x64/0xa4 [<000000000022e366>] vfs_fstatat+0x4e/0xb0 [<000000000022e4d6>] SyS_newstat+0x2e/0x54 [<00000000001146de>] sysc_noemu+0x10/0x16 [<0000020000153456>] 0x20000153456 INFO: lockdep is turned off. Last Breaking-Event-Address: [<000000000048a0ae>] zfcp_fsf_fcp_cmnd_handler+0x26/0x3b4 Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index be0317457147..aa0cd2322738 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -2069,8 +2069,6 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req) struct fcp_resp_with_ext *fcp_rsp; unsigned long flags; - zfcp_fsf_fcp_handler_common(req); - read_lock_irqsave(&req->adapter->abort_lock, flags); scpnt = req->data; @@ -2079,6 +2077,8 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req) return; } + zfcp_fsf_fcp_handler_common(req); + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED); goto skip_fsfstatus; -- cgit v1.2.3 From 6fbf25e86beef1c6719e760a241a7aef9ad145e3 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Wed, 17 Nov 2010 14:23:41 +0100 Subject: [SCSI] zfcp: Correct false abort data assignment. The request data assignment between the fsf abort initiator and its corresponding handler is not consistent and leads to an unpredictable behaviour, e.g. kernel panic. This patch fixes this issue and assigns the correct value. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index aa0cd2322738..f75707a8de2b 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -851,7 +851,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd) zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); - req->data = zfcp_sdev; + req->data = sdev; req->handler = zfcp_fsf_abort_fcp_command_handler; req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; req->qtcb->header.port_handle = zfcp_sdev->port->handle; -- cgit v1.2.3 From d3e1088d68735eb7da12f79a0c3c0d951cbc89f1 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Wed, 17 Nov 2010 14:23:42 +0100 Subject: [SCSI] zfcp: No ERP escalation on gpn_ft eval If the evaluation of GPN_FT requests wants to remove an invalid port from the system the zfcp_erp_port_shutdown function is triggered. Depending on the system status a superior action (e.g. adapter reopen) is required. This can lead to an invalid mem access of the port struct which might be freed at the time since the superior action is not holding a reference of the port which triggered this ERP action. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index d37c7331f244..63422c13c7da 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -156,6 +156,8 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) || a_status & ZFCP_STATUS_COMMON_ERP_FAILED) return 0; + if (p_status & ZFCP_STATUS_COMMON_NOESC) + return need; if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED)) need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; /* fall through */ -- cgit v1.2.3 From 14718e3cd8e9c6937114cebbf3ce5d504328da8c Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Wed, 17 Nov 2010 14:23:43 +0100 Subject: [SCSI] zfcp: Prevent usage w/o holding a reference The ERP got values assigned for which no reference was taken. This can lead to an unpredictable race condition. Fix this by only assigning the values which are required and for which a reference was pulled or is held implicitly. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 63422c13c7da..0bcd5806bd9a 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -190,6 +190,9 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &zfcp_sdev->status); erp_action = &zfcp_sdev->erp_action; + memset(erp_action, 0, sizeof(struct zfcp_erp_action)); + erp_action->port = port; + erp_action->sdev = sdev; if (!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_RUNNING)) act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; @@ -202,6 +205,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, zfcp_erp_action_dismiss_port(port); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); erp_action = &port->erp_action; + memset(erp_action, 0, sizeof(struct zfcp_erp_action)); + erp_action->port = port; if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; @@ -211,6 +216,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, zfcp_erp_action_dismiss_adapter(adapter); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); erp_action = &adapter->erp_action; + memset(erp_action, 0, sizeof(struct zfcp_erp_action)); if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; @@ -220,10 +226,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, return NULL; } - memset(erp_action, 0, sizeof(struct zfcp_erp_action)); erp_action->adapter = adapter; - erp_action->port = port; - erp_action->sdev = sdev; erp_action->action = need; erp_action->status = act_status; -- cgit v1.2.3 From e55f87531c2c1eb071a296df7eb67f83d5f0b5df Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 18 Nov 2010 14:53:18 +0100 Subject: [SCSI] zfcp: Issue FCP command without holding SCSI host_lock Interrupting the connection to the FCP channel while I/O requests are being issued can lead to this deadlock. scsi_dispatch_cmd already holds the host_lock while the recovery trigger tries to acquire the host_lock again when iterating through the scsi_devices. INFO: lockdep is turned off. BUG: spinlock lockup on CPU#1, blast/9660, 0000000078f38878 CPU: 1 Not tainted 2.6.35.7SWEN2 #2 Process blast (pid: 9660, task: 0000000071f75940, ksp: 0000000074393ac0) 0000000074393640 00000000743935c0 0000000000000002 0000000000000000 0000000074393660 00000000743935d8 00000000743935d8 00000000005590c2 0000000000000000 0000000078f38878 0000000026ede800 0000000078f38878 000000000000000d 040000000000000c 0000000074393628 0000000000000000 0000000000000000 0000000000100b2a 00000000743935c0 0000000074393600 Call Trace: ([<0000000000100a32>] show_trace+0xee/0x144) [<00000000003be202>] do_raw_spin_lock+0x112/0x178 [<000000000055d408>] _raw_spin_lock_irqsave+0x90/0xb0 [<00000000003f1514>] __scsi_iterate_devices+0x38/0xbc [<00000000004849b0>] zfcp_erp_clear_adapter_status+0xd0/0x16c [<000000000048587a>] zfcp_erp_adapter_reopen+0x3a/0xb4 [<0000000000489812>] zfcp_fsf_req_send+0x166/0x180 [<000000000048c8d6>] zfcp_fsf_fcp_cmnd+0x272/0x408 [<000000000048f864>] zfcp_scsi_queuecommand+0x11c/0x1e0 [<00000000003f1f2a>] scsi_dispatch_cmd+0x1d6/0x324 [<00000000003f9910>] scsi_request_fn+0x42c/0x56c [<00000000003828ae>] __blk_run_queue+0x86/0x140 [<000000000037f742>] elv_insert+0x11a/0x208 [<000000000038104c>] blk_insert_cloned_request+0x84/0xe4 [<000003c0032b7c64>] dm_dispatch_request+0x6c/0x94 [dm_mod] [<000003c0032b7d5c>] map_request+0xd0/0x100 [dm_mod] [<000003c0032b9a78>] dm_request_fn+0xec/0x1bc [dm_mod] [<0000000000382c0e>] generic_unplug_device+0x5a/0x6c [<000003c0032b7f98>] dm_unplug_all+0x74/0x9c [dm_mod] [<00000000001d1272>] sync_page+0x76/0x9c [<00000000001d12ba>] sync_page_killable+0x22/0x60 [<000000000055a768>] __wait_on_bit_lock+0xc0/0x124 [<00000000001d1140>] __lock_page_killable+0x78/0x84 [<00000000001d351c>] generic_file_aio_read+0x5a4/0x7e8 [<0000000000228ec0>] do_sync_read+0xc8/0x12c [<0000000000229edc>] vfs_read+0xac/0x1ac [<000000000022a0d8>] SyS_read+0x58/0xa8 [<00000000001146de>] sysc_noemu+0x10/0x16 [<00000200000493c4>] 0x200000493c4 INFO: lockdep is turned off. Call zfcp_fsf_fcp_cmnd without the host_lock and disable the interrupts when acquiring the req_q_lock. According to the patch description in "[PATCH] Eliminate error handler overload of the SCSI serial number", the serial_number is not used, so simply drop the queuecommand wrapper function and run zfcp_scsi_queuecommand without holding the host_lock. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 5 +++-- drivers/s390/scsi/zfcp_scsi.c | 7 ++----- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index f75707a8de2b..2eb7dd56ab80 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -2170,12 +2170,13 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct zfcp_qdio *qdio = adapter->qdio; struct fsf_qtcb_bottom_io *io; + unsigned long flags; if (unlikely(!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) return -EBUSY; - spin_lock(&qdio->req_q_lock); + spin_lock_irqsave(&qdio->req_q_lock, flags); if (atomic_read(&qdio->req_q_free) <= 0) { atomic_inc(&qdio->req_q_full); goto out; @@ -2239,7 +2240,7 @@ failed_scsi_cmnd: zfcp_fsf_req_free(req); scsi_cmnd->host_scribble = NULL; out: - spin_unlock(&qdio->req_q_lock); + spin_unlock_irqrestore(&qdio->req_q_lock, flags); return retval; } diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 6bd2dbc4c316..63529ed801eb 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -76,8 +76,8 @@ static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) scpnt->scsi_done(scpnt); } -static int zfcp_scsi_queuecommand_lck(struct scsi_cmnd *scpnt, - void (*done) (struct scsi_cmnd *)) +static +int zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; @@ -87,7 +87,6 @@ static int zfcp_scsi_queuecommand_lck(struct scsi_cmnd *scpnt, /* reset the status for this request */ scpnt->result = 0; scpnt->host_scribble = NULL; - scpnt->scsi_done = done; scsi_result = fc_remote_port_chkready(rport); if (unlikely(scsi_result)) { @@ -127,8 +126,6 @@ static int zfcp_scsi_queuecommand_lck(struct scsi_cmnd *scpnt, return ret; } -static DEF_SCSI_QCMD(zfcp_scsi_queuecommand) - static int zfcp_scsi_slave_alloc(struct scsi_device *sdev) { struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); -- cgit v1.2.3 From d0ddf30fdd2b98fb547ffa33bb79a7a96ef8d7dd Mon Sep 17 00:00:00 2001 From: Einar Lueck Date: Wed, 8 Dec 2010 02:57:58 +0000 Subject: qeth: support ipv6 query arp cache for HiperSockets Function qeth_l3_arp_query now queries for IPv6 addresses, too, if QETH_QARP_WITH_IPV6 is passed as parameter to the ioctl. HiperSockets and GuestLAN in HiperSockets mode provide corresponding entries. Signed-off-by: Einar Lueck Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- arch/s390/include/asm/qeth.h | 51 ++++++++-- drivers/s390/net/qeth_core_mpc.h | 2 +- drivers/s390/net/qeth_l3_main.c | 215 ++++++++++++++++++++++++++------------- 3 files changed, 185 insertions(+), 83 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/qeth.h b/arch/s390/include/asm/qeth.h index 06cbd1e8c943..90efda0b137d 100644 --- a/arch/s390/include/asm/qeth.h +++ b/arch/s390/include/asm/qeth.h @@ -28,39 +28,70 @@ struct qeth_arp_cache_entry { __u8 reserved2[32]; } __attribute__ ((packed)); +enum qeth_arp_ipaddrtype { + QETHARP_IP_ADDR_V4 = 1, + QETHARP_IP_ADDR_V6 = 2, +}; +struct qeth_arp_entrytype { + __u8 mac; + __u8 ip; +} __attribute__((packed)); + +#define QETH_QARP_MEDIASPECIFIC_BYTES 32 +#define QETH_QARP_MACADDRTYPE_BYTES 1 struct qeth_arp_qi_entry7 { - __u8 media_specific[32]; - __u8 macaddr_type; - __u8 ipaddr_type; + __u8 media_specific[QETH_QARP_MEDIASPECIFIC_BYTES]; + struct qeth_arp_entrytype type; __u8 macaddr[6]; __u8 ipaddr[4]; } __attribute__((packed)); +struct qeth_arp_qi_entry7_ipv6 { + __u8 media_specific[QETH_QARP_MEDIASPECIFIC_BYTES]; + struct qeth_arp_entrytype type; + __u8 macaddr[6]; + __u8 ipaddr[16]; +} __attribute__((packed)); + struct qeth_arp_qi_entry7_short { - __u8 macaddr_type; - __u8 ipaddr_type; + struct qeth_arp_entrytype type; __u8 macaddr[6]; __u8 ipaddr[4]; } __attribute__((packed)); +struct qeth_arp_qi_entry7_short_ipv6 { + struct qeth_arp_entrytype type; + __u8 macaddr[6]; + __u8 ipaddr[16]; +} __attribute__((packed)); + struct qeth_arp_qi_entry5 { - __u8 media_specific[32]; - __u8 macaddr_type; - __u8 ipaddr_type; + __u8 media_specific[QETH_QARP_MEDIASPECIFIC_BYTES]; + struct qeth_arp_entrytype type; __u8 ipaddr[4]; } __attribute__((packed)); +struct qeth_arp_qi_entry5_ipv6 { + __u8 media_specific[QETH_QARP_MEDIASPECIFIC_BYTES]; + struct qeth_arp_entrytype type; + __u8 ipaddr[16]; +} __attribute__((packed)); + struct qeth_arp_qi_entry5_short { - __u8 macaddr_type; - __u8 ipaddr_type; + struct qeth_arp_entrytype type; __u8 ipaddr[4]; } __attribute__((packed)); +struct qeth_arp_qi_entry5_short_ipv6 { + struct qeth_arp_entrytype type; + __u8 ipaddr[16]; +} __attribute__((packed)); /* * can be set by user if no "media specific information" is wanted * -> saves a lot of space in user space buffer */ #define QETH_QARP_STRIP_ENTRIES 0x8000 +#define QETH_QARP_WITH_IPV6 0x4000 #define QETH_QARP_REQUEST_MASK 0x00ff /* data sent to user space as result of query arp ioctl */ diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index e37dd8c4bf4e..07d588867b57 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -333,7 +333,7 @@ struct qeth_arp_query_data { __u16 request_bits; __u16 reply_bits; __u32 no_entries; - char data; + char data; /* only for replies */ } __attribute__((packed)); /* used as parameter for arp_query reply */ diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index a1abb37db000..a7590551e574 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -30,6 +30,7 @@ #include "qeth_l3.h" + static int qeth_l3_set_offline(struct ccwgroup_device *); static int qeth_l3_recover(void *); static int qeth_l3_stop(struct net_device *); @@ -2455,22 +2456,46 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries) return rc; } -static void qeth_l3_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo, - struct qeth_arp_query_data *qdata, int entry_size, - int uentry_size) +static __u32 get_arp_entry_size(struct qeth_card *card, + struct qeth_arp_query_data *qdata, + struct qeth_arp_entrytype *type, __u8 strip_entries) { - char *entry_ptr; - char *uentry_ptr; - int i; + __u32 rc; + __u8 is_hsi; - entry_ptr = (char *)&qdata->data; - uentry_ptr = (char *)(qinfo->udata + qinfo->udata_offset); - for (i = 0; i < qdata->no_entries; ++i) { - /* strip off 32 bytes "media specific information" */ - memcpy(uentry_ptr, (entry_ptr + 32), entry_size - 32); - entry_ptr += entry_size; - uentry_ptr += uentry_size; + is_hsi = qdata->reply_bits == 5; + if (type->ip == QETHARP_IP_ADDR_V4) { + QETH_CARD_TEXT(card, 4, "arpev4"); + if (strip_entries) { + rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5_short) : + sizeof(struct qeth_arp_qi_entry7_short); + } else { + rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5) : + sizeof(struct qeth_arp_qi_entry7); + } + } else if (type->ip == QETHARP_IP_ADDR_V6) { + QETH_CARD_TEXT(card, 4, "arpev6"); + if (strip_entries) { + rc = is_hsi ? + sizeof(struct qeth_arp_qi_entry5_short_ipv6) : + sizeof(struct qeth_arp_qi_entry7_short_ipv6); + } else { + rc = is_hsi ? + sizeof(struct qeth_arp_qi_entry5_ipv6) : + sizeof(struct qeth_arp_qi_entry7_ipv6); + } + } else { + QETH_CARD_TEXT(card, 4, "arpinv"); + rc = 0; } + + return rc; +} + +static int arpentry_matches_prot(struct qeth_arp_entrytype *type, __u16 prot) +{ + return (type->ip == QETHARP_IP_ADDR_V4 && prot == QETH_PROT_IPV4) || + (type->ip == QETHARP_IP_ADDR_V6 && prot == QETH_PROT_IPV6); } static int qeth_l3_arp_query_cb(struct qeth_card *card, @@ -2479,72 +2504,77 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card, struct qeth_ipa_cmd *cmd; struct qeth_arp_query_data *qdata; struct qeth_arp_query_info *qinfo; - int entry_size; - int uentry_size; int i; + int e; + int entrybytes_done; + int stripped_bytes; + __u8 do_strip_entries; - QETH_CARD_TEXT(card, 4, "arpquecb"); + QETH_CARD_TEXT(card, 3, "arpquecb"); qinfo = (struct qeth_arp_query_info *) reply->param; cmd = (struct qeth_ipa_cmd *) data; + QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.prot_version); if (cmd->hdr.return_code) { - QETH_CARD_TEXT_(card, 4, "qaer1%i", cmd->hdr.return_code); + QETH_CARD_TEXT(card, 4, "arpcberr"); + QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code); return 0; } if (cmd->data.setassparms.hdr.return_code) { cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code; - QETH_CARD_TEXT_(card, 4, "qaer2%i", cmd->hdr.return_code); + QETH_CARD_TEXT(card, 4, "setaperr"); + QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code); return 0; } qdata = &cmd->data.setassparms.data.query_arp; - switch (qdata->reply_bits) { - case 5: - uentry_size = entry_size = sizeof(struct qeth_arp_qi_entry5); - if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) - uentry_size = sizeof(struct qeth_arp_qi_entry5_short); - break; - case 7: - /* fall through to default */ - default: - /* tr is the same as eth -> entry7 */ - uentry_size = entry_size = sizeof(struct qeth_arp_qi_entry7); - if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) - uentry_size = sizeof(struct qeth_arp_qi_entry7_short); - break; - } - /* check if there is enough room in userspace */ - if ((qinfo->udata_len - qinfo->udata_offset) < - qdata->no_entries * uentry_size){ - QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM); - cmd->hdr.return_code = -ENOMEM; - goto out_error; - } - QETH_CARD_TEXT_(card, 4, "anore%i", - cmd->data.setassparms.hdr.number_of_replies); - QETH_CARD_TEXT_(card, 4, "aseqn%i", cmd->data.setassparms.hdr.seq_no); QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries); - if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) { - /* strip off "media specific information" */ - qeth_l3_copy_arp_entries_stripped(qinfo, qdata, entry_size, - uentry_size); - } else - /*copy entries to user buffer*/ - memcpy(qinfo->udata + qinfo->udata_offset, - (char *)&qdata->data, qdata->no_entries*uentry_size); + do_strip_entries = (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) > 0; + stripped_bytes = do_strip_entries ? QETH_QARP_MEDIASPECIFIC_BYTES : 0; + entrybytes_done = 0; + for (e = 0; e < qdata->no_entries; ++e) { + char *cur_entry; + __u32 esize; + struct qeth_arp_entrytype *etype; + + cur_entry = &qdata->data + entrybytes_done; + etype = &((struct qeth_arp_qi_entry5 *) cur_entry)->type; + if (!arpentry_matches_prot(etype, cmd->hdr.prot_version)) { + QETH_CARD_TEXT(card, 4, "pmis"); + QETH_CARD_TEXT_(card, 4, "%i", etype->ip); + break; + } + esize = get_arp_entry_size(card, qdata, etype, + do_strip_entries); + QETH_CARD_TEXT_(card, 5, "esz%i", esize); + if (!esize) + break; + + if ((qinfo->udata_len - qinfo->udata_offset) < esize) { + QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM); + cmd->hdr.return_code = -ENOMEM; + goto out_error; + } - qinfo->no_entries += qdata->no_entries; - qinfo->udata_offset += (qdata->no_entries*uentry_size); + memcpy(qinfo->udata + qinfo->udata_offset, + &qdata->data + entrybytes_done + stripped_bytes, + esize); + entrybytes_done += esize + stripped_bytes; + qinfo->udata_offset += esize; + ++qinfo->no_entries; + } /* check if all replies received ... */ if (cmd->data.setassparms.hdr.seq_no < cmd->data.setassparms.hdr.number_of_replies) return 1; + QETH_CARD_TEXT_(card, 4, "nove%i", qinfo->no_entries); memcpy(qinfo->udata, &qinfo->no_entries, 4); /* keep STRIP_ENTRIES flag so the user program can distinguish * stripped entries from normal ones */ if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) qdata->reply_bits |= QETH_QARP_STRIP_ENTRIES; memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET, &qdata->reply_bits, 2); + QETH_CARD_TEXT_(card, 4, "rc%i", 0); return 0; out_error: i = 0; @@ -2567,45 +2597,86 @@ static int qeth_l3_send_ipa_arp_cmd(struct qeth_card *card, reply_cb, reply_param); } -static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata) +static int qeth_l3_query_arp_cache_info(struct qeth_card *card, + enum qeth_prot_versions prot, + struct qeth_arp_query_info *qinfo) { struct qeth_cmd_buffer *iob; - struct qeth_arp_query_info qinfo = {0, }; + struct qeth_ipa_cmd *cmd; int tmp; int rc; + QETH_CARD_TEXT_(card, 3, "qarpipv%i", prot); + + iob = qeth_l3_get_setassparms_cmd(card, IPA_ARP_PROCESSING, + IPA_CMD_ASS_ARP_QUERY_INFO, + sizeof(struct qeth_arp_query_data) - sizeof(char), + prot); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.setassparms.data.query_arp.request_bits = 0x000F; + cmd->data.setassparms.data.query_arp.reply_bits = 0; + cmd->data.setassparms.data.query_arp.no_entries = 0; + rc = qeth_l3_send_ipa_arp_cmd(card, iob, + QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN, + qeth_l3_arp_query_cb, (void *)qinfo); + if (rc) { + tmp = rc; + QETH_DBF_MESSAGE(2, + "Error while querying ARP cache on %s: %s " + "(0x%x/%d)\n", QETH_CARD_IFNAME(card), + qeth_l3_arp_get_error_cause(&rc), tmp, tmp); + } + + return rc; +} + +static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata) +{ + struct qeth_arp_query_info qinfo = {0, }; + int rc; + QETH_CARD_TEXT(card, 3, "arpquery"); if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/ IPA_ARP_PROCESSING)) { - return -EOPNOTSUPP; + QETH_CARD_TEXT(card, 3, "arpqnsup"); + rc = -EOPNOTSUPP; + goto out; } /* get size of userspace buffer and mask_bits -> 6 bytes */ - if (copy_from_user(&qinfo, udata, 6)) - return -EFAULT; + if (copy_from_user(&qinfo, udata, 6)) { + rc = -EFAULT; + goto out; + } qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL); - if (!qinfo.udata) - return -ENOMEM; + if (!qinfo.udata) { + rc = -ENOMEM; + goto out; + } qinfo.udata_offset = QETH_QARP_ENTRIES_OFFSET; - iob = qeth_l3_get_setassparms_cmd(card, IPA_ARP_PROCESSING, - IPA_CMD_ASS_ARP_QUERY_INFO, - sizeof(int), QETH_PROT_IPV4); - - rc = qeth_l3_send_ipa_arp_cmd(card, iob, - QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN, - qeth_l3_arp_query_cb, (void *)&qinfo); + rc = qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV4, &qinfo); if (rc) { - tmp = rc; - QETH_DBF_MESSAGE(2, "Error while querying ARP cache on %s: %s " - "(0x%x/%d)\n", QETH_CARD_IFNAME(card), - qeth_l3_arp_get_error_cause(&rc), tmp, tmp); if (copy_to_user(udata, qinfo.udata, 4)) rc = -EFAULT; + goto free_and_out; } else { - if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) +#ifdef CONFIG_QETH_IPV6 + if (qinfo.mask_bits & QETH_QARP_WITH_IPV6) { + /* fails in case of GuestLAN QDIO mode */ + qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV6, + &qinfo); + } +#endif + if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) { + QETH_CARD_TEXT(card, 4, "qactf"); rc = -EFAULT; + goto free_and_out; + } + QETH_CARD_TEXT_(card, 4, "qacts"); } +free_and_out: kfree(qinfo.udata); +out: return rc; } -- cgit v1.2.3 From f154b79cd7db221240ab6e8e4d844d3a3f10b04c Mon Sep 17 00:00:00 2001 From: Einar Lueck Date: Wed, 8 Dec 2010 02:57:59 +0000 Subject: qeth: support VIPA add/del in offline mode Only work through the IP adddress to do list if the card is UP or SOFTSETUP. Enables to configure VIPA add/del in offline mode. Signed-off-by: Einar Lueck Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index a7590551e574..d5e40c3e4bc3 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -456,8 +456,11 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) QETH_CARD_TEXT(card, 2, "sdiplist"); QETH_CARD_HEX(card, 2, &card, sizeof(void *)); - if (card->options.sniffer) + if ((card->state != CARD_STATE_UP && + card->state != CARD_STATE_SOFTSETUP) || card->options.sniffer) { return; + } + spin_lock_irqsave(&card->ip_lock, flags); tbd_list = card->ip_tbd_list; card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); -- cgit v1.2.3 From 91d4576bfe87980b1b86305c29912d96b96ce98e Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Wed, 8 Dec 2010 02:58:00 +0000 Subject: qeth: l3 add vlan hdr in passthru frames OSA l3 mode is hw accelerated VLAN only for IPv4. Take care we add the vlan hdr to a passthru frame in the device driver. Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index d5e40c3e4bc3..e227e465bfc4 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3115,7 +3115,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_pull(new_skb, ETH_HLEN); } - if (ipv == 6 && card->vlangrp && + if (ipv != 4 && card->vlangrp && vlan_tx_tag_present(new_skb)) { skb_push(new_skb, VLAN_HLEN); skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4); -- cgit v1.2.3 From a6a5ff26975c87a97f88c6ea077c325ff20c4cf2 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 8 Dec 2010 02:58:01 +0000 Subject: qeth: buffer count imbalance The used buffers counter is not incremented in case of an error so the counter can become negative. Increment the used buffers counter before checking for errors. Signed-off-by: Jan Glauber Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index e6b2df0e73f5..b7d9dc0adc62 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2840,6 +2840,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() - queue->card->perf_stats.outbound_do_qdio_start_time; + atomic_add(count, &queue->used_buffers); if (rc) { queue->card->stats.tx_errors += count; /* ignore temporary SIGA errors without busy condition */ @@ -2853,7 +2854,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, qeth_schedule_recovery(queue->card); return; } - atomic_add(count, &queue->used_buffers); if (queue->card->options.performance_stats) queue->card->perf_stats.bufs_sent += count; } -- cgit v1.2.3 From 4a6f4fe8377720e5a279fdbb769946c242e936d3 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Mon, 6 Dec 2010 11:16:24 -0600 Subject: drivers: Replace __get_cpu_var with __this_cpu_read if not used for an address. __get_cpu_var() can be replaced with this_cpu_read and will then use a single read instruction with implied address calculation to access the correct per cpu instance. However, the address of a per cpu variable passed to __this_cpu_read() cannot be determed (since its an implied address conversion through segment prefixes). Therefore apply this only to uses of __get_cpu_var where the addres of the variable is not used. V3->V4: - Move one instance of this_cpu_inc_return to a later patch so that this one can go in without percpu infrastructrure changes. Sedat: fixed compile failure caused by an extra ')'. Cc: Neil Horman Cc: Martin Schwidefsky Cc: Sedat Dilek Acked-by: H. Peter Anvin Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/acpi/processor_idle.c | 6 +++--- drivers/cpuidle/cpuidle.c | 2 +- drivers/s390/cio/cio.c | 2 +- drivers/staging/speakup/fakekey.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index dcb38f8ddfda..a765b823aa9e 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -746,7 +746,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, struct acpi_processor *pr; struct acpi_processor_cx *cx = cpuidle_get_statedata(state); - pr = __get_cpu_var(processors); + pr = __this_cpu_read(processors); if (unlikely(!pr)) return 0; @@ -787,7 +787,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, s64 idle_time_ns; s64 idle_time; - pr = __get_cpu_var(processors); + pr = __this_cpu_read(processors); if (unlikely(!pr)) return 0; @@ -864,7 +864,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, s64 idle_time; - pr = __get_cpu_var(processors); + pr = __this_cpu_read(processors); if (unlikely(!pr)) return 0; diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index a50710843378..978ff292a3fa 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -49,7 +49,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev); */ static void cpuidle_idle_call(void) { - struct cpuidle_device *dev = __get_cpu_var(cpuidle_devices); + struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); struct cpuidle_state *target_state; int next_state; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index f4e6cf3aceb8..430f875006f2 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -619,7 +619,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs) s390_idle_check(regs, S390_lowcore.int_clock, S390_lowcore.async_enter_timer); irq_enter(); - __get_cpu_var(s390_idle).nohz_delay = 1; + __this_cpu_write(s390_idle.nohz_delay, 1); if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) /* Serve timer interrupts first. */ clock_comparator_work(); diff --git a/drivers/staging/speakup/fakekey.c b/drivers/staging/speakup/fakekey.c index 65b231178f05..bf4ec68ac2eb 100644 --- a/drivers/staging/speakup/fakekey.c +++ b/drivers/staging/speakup/fakekey.c @@ -78,10 +78,10 @@ void speakup_fake_down_arrow(void) /* don't change CPU */ preempt_disable(); - __get_cpu_var(reporting_keystroke) = true; + __this_cpu_write(reporting_keystroke, true); input_report_key(virt_keyboard, KEY_DOWN, PRESSED); input_report_key(virt_keyboard, KEY_DOWN, RELEASED); - __get_cpu_var(reporting_keystroke) = false; + __this_cpu_write(reporting_keystroke, false); /* reenable preemption */ preempt_enable(); -- cgit v1.2.3 From ae0904f60fab7cb20c48d32eefdd735e478b91fb Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Thu, 2 Dec 2010 15:16:12 +0100 Subject: [SCSI] zfcp: Redesign of the debug tracing for recovery actions. The tracing environment of the zfcp LLD has become very bulky and hard to maintain. Small changes involve a large modification process which is error-prone and not effective. This patch is the first of a set to redesign the zfcp tracing to a more straight-forward and easy to extend scheme. It removes all interpretation and visualization parts and focuses on bare logging of the information. This patch deals with all trace records of the zfcp error recovery. Signed-off-by: Swen schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 281 ++++++++++--------------------------------- drivers/s390/scsi/zfcp_dbf.h | 100 ++++++++------- drivers/s390/scsi/zfcp_erp.c | 31 ++--- drivers/s390/scsi/zfcp_ext.h | 12 +- 4 files changed, 139 insertions(+), 285 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 2cdd6b28ff7f..675503628cc9 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -50,11 +50,6 @@ static void zfcp_dbf_tag(char **p, const char *label, const char *tag) *p += sprintf(*p, "\n"); } -static void zfcp_dbf_outs(char **buf, const char *s1, const char *s2) -{ - *buf += sprintf(*buf, "%-24s%s\n", s1, s2); -} - static void zfcp_dbf_out(char **buf, const char *s, const char *format, ...) { va_list arg; @@ -439,241 +434,96 @@ static struct debug_view zfcp_dbf_hba_view = { .format_proc = zfcp_dbf_hba_view_format, }; -static const char *zfcp_dbf_rec_tags[] = { - [ZFCP_REC_DBF_ID_THREAD] = "thread", - [ZFCP_REC_DBF_ID_TARGET] = "target", - [ZFCP_REC_DBF_ID_TRIGGER] = "trigger", - [ZFCP_REC_DBF_ID_ACTION] = "action", -}; - -static int zfcp_dbf_rec_view_format(debug_info_t *id, struct debug_view *view, - char *buf, const char *_rec) +static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec, + struct zfcp_adapter *adapter, + struct zfcp_port *port, + struct scsi_device *sdev) { - struct zfcp_dbf_rec_record *r = (struct zfcp_dbf_rec_record *)_rec; - char *p = buf; - char hint[ZFCP_DBF_ID_SIZE + 1]; - - memcpy(hint, r->id2, ZFCP_DBF_ID_SIZE); - hint[ZFCP_DBF_ID_SIZE] = 0; - zfcp_dbf_outs(&p, "tag", zfcp_dbf_rec_tags[r->id]); - zfcp_dbf_outs(&p, "hint", hint); - switch (r->id) { - case ZFCP_REC_DBF_ID_THREAD: - zfcp_dbf_out(&p, "total", "%d", r->u.thread.total); - zfcp_dbf_out(&p, "ready", "%d", r->u.thread.ready); - zfcp_dbf_out(&p, "running", "%d", r->u.thread.running); - break; - case ZFCP_REC_DBF_ID_TARGET: - zfcp_dbf_out(&p, "reference", "0x%016Lx", r->u.target.ref); - zfcp_dbf_out(&p, "status", "0x%08x", r->u.target.status); - zfcp_dbf_out(&p, "erp_count", "%d", r->u.target.erp_count); - zfcp_dbf_out(&p, "d_id", "0x%06x", r->u.target.d_id); - zfcp_dbf_out(&p, "wwpn", "0x%016Lx", r->u.target.wwpn); - zfcp_dbf_out(&p, "fcp_lun", "0x%016Lx", r->u.target.fcp_lun); - break; - case ZFCP_REC_DBF_ID_TRIGGER: - zfcp_dbf_out(&p, "reference", "0x%016Lx", r->u.trigger.ref); - zfcp_dbf_out(&p, "erp_action", "0x%016Lx", r->u.trigger.action); - zfcp_dbf_out(&p, "requested", "%d", r->u.trigger.want); - zfcp_dbf_out(&p, "executed", "%d", r->u.trigger.need); - zfcp_dbf_out(&p, "wwpn", "0x%016Lx", r->u.trigger.wwpn); - zfcp_dbf_out(&p, "fcp_lun", "0x%016Lx", r->u.trigger.fcp_lun); - zfcp_dbf_out(&p, "adapter_status", "0x%08x", r->u.trigger.as); - zfcp_dbf_out(&p, "port_status", "0x%08x", r->u.trigger.ps); - zfcp_dbf_out(&p, "lun_status", "0x%08x", r->u.trigger.ls); - break; - case ZFCP_REC_DBF_ID_ACTION: - zfcp_dbf_out(&p, "erp_action", "0x%016Lx", r->u.action.action); - zfcp_dbf_out(&p, "fsf_req", "0x%016Lx", r->u.action.fsf_req); - zfcp_dbf_out(&p, "status", "0x%08Lx", r->u.action.status); - zfcp_dbf_out(&p, "step", "0x%08Lx", r->u.action.step); - break; + rec->adapter_status = atomic_read(&adapter->status); + if (port) { + rec->port_status = atomic_read(&port->status); + rec->wwpn = port->wwpn; + rec->d_id = port->d_id; + } + if (sdev) { + rec->lun_status = atomic_read(&sdev_to_zfcp(sdev)->status); + rec->lun = zfcp_scsi_dev_lun(sdev); } - p += sprintf(p, "\n"); - return p - buf; } -static struct debug_view zfcp_dbf_rec_view = { - .name = "structured", - .header_proc = zfcp_dbf_view_header, - .format_proc = zfcp_dbf_rec_view_format, -}; - /** - * zfcp_dbf_rec_thread - trace event related to recovery thread operation - * @id2: identifier for event - * @dbf: reference to dbf structure - * This function assumes that the caller is holding erp_lock. + * zfcp_dbf_rec_trig - trace event related to triggered recovery + * @tag: identifier for event + * @adapter: adapter on which the erp_action should run + * @port: remote port involved in the erp_action + * @sdev: scsi device involved in the erp_action + * @want: wanted erp_action + * @need: required erp_action + * + * The adapter->erp_lock has to be held. */ -void zfcp_dbf_rec_thread(char *id2, struct zfcp_dbf *dbf) +void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter, + struct zfcp_port *port, struct scsi_device *sdev, + u8 want, u8 need) { - struct zfcp_adapter *adapter = dbf->adapter; - struct zfcp_dbf_rec_record *r = &dbf->rec_buf; - unsigned long flags = 0; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_dbf_rec *rec = &dbf->rec_buf; struct list_head *entry; - unsigned ready = 0, running = 0, total; - - list_for_each(entry, &adapter->erp_ready_head) - ready++; - list_for_each(entry, &adapter->erp_running_head) - running++; - total = adapter->erp_total_count; - - spin_lock_irqsave(&dbf->rec_lock, flags); - memset(r, 0, sizeof(*r)); - r->id = ZFCP_REC_DBF_ID_THREAD; - memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); - r->u.thread.total = total; - r->u.thread.ready = ready; - r->u.thread.running = running; - debug_event(dbf->rec, 6, r, sizeof(*r)); - spin_unlock_irqrestore(&dbf->rec_lock, flags); -} - -/** - * zfcp_dbf_rec_thread - trace event related to recovery thread operation - * @id2: identifier for event - * @adapter: adapter - * This function assumes that the caller does not hold erp_lock. - */ -void zfcp_dbf_rec_thread_lock(char *id2, struct zfcp_dbf *dbf) -{ - struct zfcp_adapter *adapter = dbf->adapter; - unsigned long flags; - - read_lock_irqsave(&adapter->erp_lock, flags); - zfcp_dbf_rec_thread(id2, dbf); - read_unlock_irqrestore(&adapter->erp_lock, flags); -} - -static void zfcp_dbf_rec_target(char *id2, void *ref, struct zfcp_dbf *dbf, - atomic_t *status, atomic_t *erp_count, u64 wwpn, - u32 d_id, u64 fcp_lun) -{ - struct zfcp_dbf_rec_record *r = &dbf->rec_buf; unsigned long flags; spin_lock_irqsave(&dbf->rec_lock, flags); - memset(r, 0, sizeof(*r)); - r->id = ZFCP_REC_DBF_ID_TARGET; - memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); - r->u.target.ref = (unsigned long)ref; - r->u.target.status = atomic_read(status); - r->u.target.wwpn = wwpn; - r->u.target.d_id = d_id; - r->u.target.fcp_lun = fcp_lun; - r->u.target.erp_count = atomic_read(erp_count); - debug_event(dbf->rec, 3, r, sizeof(*r)); - spin_unlock_irqrestore(&dbf->rec_lock, flags); -} - -/** - * zfcp_dbf_rec_adapter - trace event for adapter state change - * @id: identifier for trigger of state change - * @ref: additional reference (e.g. request) - * @dbf: reference to dbf structure - */ -void zfcp_dbf_rec_adapter(char *id, void *ref, struct zfcp_dbf *dbf) -{ - struct zfcp_adapter *adapter = dbf->adapter; + memset(rec, 0, sizeof(*rec)); - zfcp_dbf_rec_target(id, ref, dbf, &adapter->status, - &adapter->erp_counter, 0, 0, - ZFCP_DBF_INVALID_LUN); -} + rec->id = ZFCP_DBF_REC_TRIG; + memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); + zfcp_dbf_set_common(rec, adapter, port, sdev); -/** - * zfcp_dbf_rec_port - trace event for port state change - * @id: identifier for trigger of state change - * @ref: additional reference (e.g. request) - * @port: port - */ -void zfcp_dbf_rec_port(char *id, void *ref, struct zfcp_port *port) -{ - struct zfcp_dbf *dbf = port->adapter->dbf; + list_for_each(entry, &adapter->erp_ready_head) + rec->u.trig.ready++; - zfcp_dbf_rec_target(id, ref, dbf, &port->status, - &port->erp_counter, port->wwpn, port->d_id, - ZFCP_DBF_INVALID_LUN); -} + list_for_each(entry, &adapter->erp_running_head) + rec->u.trig.running++; -/** - * zfcp_dbf_rec_lun - trace event for LUN state change - * @id: identifier for trigger of state change - * @ref: additional reference (e.g. request) - * @sdev: SCSI device - */ -void zfcp_dbf_rec_lun(char *id, void *ref, struct scsi_device *sdev) -{ - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - struct zfcp_port *port = zfcp_sdev->port; - struct zfcp_dbf *dbf = port->adapter->dbf; + rec->u.trig.want = want; + rec->u.trig.need = need; - zfcp_dbf_rec_target(id, ref, dbf, &zfcp_sdev->status, - &zfcp_sdev->erp_counter, port->wwpn, port->d_id, - zfcp_scsi_dev_lun(sdev)); + debug_event(dbf->rec, 1, rec, sizeof(*rec)); + spin_unlock_irqrestore(&dbf->rec_lock, flags); } + /** - * zfcp_dbf_rec_trigger - trace event for triggered error recovery - * @id2: identifier for error recovery trigger - * @ref: additional reference (e.g. request) - * @want: originally requested error recovery action - * @need: error recovery action actually initiated - * @action: address of error recovery action struct - * @adapter: adapter - * @port: port - * @sdev: SCSI device + * zfcp_dbf_rec_run - trace event related to running recovery + * @tag: identifier for event + * @erp: erp_action running */ -void zfcp_dbf_rec_trigger(char *id2, void *ref, u8 want, u8 need, void *action, - struct zfcp_adapter *adapter, struct zfcp_port *port, - struct scsi_device *sdev) +void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp) { - struct zfcp_dbf *dbf = adapter->dbf; - struct zfcp_dbf_rec_record *r = &dbf->rec_buf; + struct zfcp_dbf *dbf = erp->adapter->dbf; + struct zfcp_dbf_rec *rec = &dbf->rec_buf; unsigned long flags; spin_lock_irqsave(&dbf->rec_lock, flags); - memset(r, 0, sizeof(*r)); - r->id = ZFCP_REC_DBF_ID_TRIGGER; - memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); - r->u.trigger.ref = (unsigned long)ref; - r->u.trigger.want = want; - r->u.trigger.need = need; - r->u.trigger.action = (unsigned long)action; - r->u.trigger.as = atomic_read(&adapter->status); - if (port) { - r->u.trigger.ps = atomic_read(&port->status); - r->u.trigger.wwpn = port->wwpn; - } - if (sdev) - r->u.trigger.ls = atomic_read(&sdev_to_zfcp(sdev)->status); - r->u.trigger.fcp_lun = sdev ? zfcp_scsi_dev_lun(sdev) : - ZFCP_DBF_INVALID_LUN; - debug_event(dbf->rec, action ? 1 : 4, r, sizeof(*r)); - spin_unlock_irqrestore(&dbf->rec_lock, flags); -} + memset(rec, 0, sizeof(*rec)); -/** - * zfcp_dbf_rec_action - trace event showing progress of recovery action - * @id2: identifier - * @erp_action: error recovery action struct pointer - */ -void zfcp_dbf_rec_action(char *id2, struct zfcp_erp_action *erp_action) -{ - struct zfcp_dbf *dbf = erp_action->adapter->dbf; - struct zfcp_dbf_rec_record *r = &dbf->rec_buf; - unsigned long flags; + rec->id = ZFCP_DBF_REC_RUN; + memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); + zfcp_dbf_set_common(rec, erp->adapter, erp->port, erp->sdev); - spin_lock_irqsave(&dbf->rec_lock, flags); - memset(r, 0, sizeof(*r)); - r->id = ZFCP_REC_DBF_ID_ACTION; - memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); - r->u.action.action = (unsigned long)erp_action; - r->u.action.status = erp_action->status; - r->u.action.step = erp_action->step; - r->u.action.fsf_req = erp_action->fsf_req_id; - debug_event(dbf->rec, 5, r, sizeof(*r)); + rec->u.run.fsf_req_id = erp->fsf_req_id; + rec->u.run.rec_status = erp->status; + rec->u.run.rec_step = erp->step; + rec->u.run.rec_action = erp->action; + + if (erp->sdev) + rec->u.run.rec_count = + atomic_read(&sdev_to_zfcp(erp->sdev)->erp_counter); + else if (erp->port) + rec->u.run.rec_count = atomic_read(&erp->port->erp_counter); + else + rec->u.run.rec_count = atomic_read(&erp->adapter->erp_counter); + + debug_event(dbf->rec, 1, rec, sizeof(*rec)); spin_unlock_irqrestore(&dbf->rec_lock, flags); } @@ -1019,8 +869,7 @@ int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter) /* debug feature area which records recovery activity */ sprintf(dbf_name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev)); - dbf->rec = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_rec_view, - sizeof(struct zfcp_dbf_rec_record)); + dbf->rec = zfcp_dbf_reg(dbf_name, 3, NULL, sizeof(struct zfcp_dbf_rec)); if (!dbf->rec) goto err_out; diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 04081b1b62b4..2e823d4ede6e 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -27,6 +27,7 @@ #include "zfcp_fsf.h" #include "zfcp_def.h" +#define ZFCP_DBF_TAG_LEN 7 #define ZFCP_DBF_TAG_SIZE 4 #define ZFCP_DBF_ID_SIZE 7 @@ -40,57 +41,72 @@ struct zfcp_dbf_dump { u8 data[]; /* dump data */ } __attribute__ ((packed)); -struct zfcp_dbf_rec_record_thread { - u32 total; +/** + * struct zfcp_dbf_rec_trigger - trace record for triggered recovery action + * @ready: number of ready recovery actions + * @running: number of running recovery actions + * @want: wanted recovery action + * @need: needed recovery action + */ +struct zfcp_dbf_rec_trigger { u32 ready; u32 running; -}; - -struct zfcp_dbf_rec_record_target { - u64 ref; - u32 status; - u32 d_id; - u64 wwpn; - u64 fcp_lun; - u32 erp_count; -}; - -struct zfcp_dbf_rec_record_trigger { u8 want; u8 need; - u32 as; - u32 ps; - u32 ls; - u64 ref; - u64 action; - u64 wwpn; - u64 fcp_lun; -}; +} __packed; + +/** + * struct zfcp_dbf_rec_running - trace record for running recovery + * @fsf_req_id: request id for fsf requests + * @rec_status: status of the fsf request + * @rec_step: current step of the recovery action + * rec_count: recovery counter + */ +struct zfcp_dbf_rec_running { + u64 fsf_req_id; + u32 rec_status; + u16 rec_step; + u8 rec_action; + u8 rec_count; +} __packed; -struct zfcp_dbf_rec_record_action { - u32 status; - u32 step; - u64 action; - u64 fsf_req; +/** + * enum zfcp_dbf_rec_id - recovery trace record id + * @ZFCP_DBF_REC_TRIG: triggered recovery identifier + * @ZFCP_DBF_REC_RUN: running recovery identifier + */ +enum zfcp_dbf_rec_id { + ZFCP_DBF_REC_TRIG = 1, + ZFCP_DBF_REC_RUN = 2, }; -struct zfcp_dbf_rec_record { +/** + * struct zfcp_dbf_rec - trace record for error recovery actions + * @id: unique number of recovery record type + * @tag: identifier string specifying the location of initiation + * @lun: logical unit number + * @wwpn: word wide port number + * @d_id: destination ID + * @adapter_status: current status of the adapter + * @port_status: current status of the port + * @lun_status: current status of the lun + * @u.trig: structure zfcp_dbf_rec_trigger + * @u.run: structure zfcp_dbf_rec_running + */ +struct zfcp_dbf_rec { u8 id; - char id2[7]; + char tag[ZFCP_DBF_TAG_LEN]; + u64 lun; + u64 wwpn; + u32 d_id; + u32 adapter_status; + u32 port_status; + u32 lun_status; union { - struct zfcp_dbf_rec_record_action action; - struct zfcp_dbf_rec_record_thread thread; - struct zfcp_dbf_rec_record_target target; - struct zfcp_dbf_rec_record_trigger trigger; + struct zfcp_dbf_rec_trigger trig; + struct zfcp_dbf_rec_running run; } u; -}; - -enum { - ZFCP_REC_DBF_ID_ACTION, - ZFCP_REC_DBF_ID_THREAD, - ZFCP_REC_DBF_ID_TARGET, - ZFCP_REC_DBF_ID_TRIGGER, -}; +} __packed; struct zfcp_dbf_hba_record_response { u32 fsf_command; @@ -232,7 +248,7 @@ struct zfcp_dbf { spinlock_t hba_lock; spinlock_t san_lock; spinlock_t scsi_lock; - struct zfcp_dbf_rec_record rec_buf; + struct zfcp_dbf_rec rec_buf; struct zfcp_dbf_hba_record hba_buf; struct zfcp_dbf_san_record san_buf; struct zfcp_dbf_scsi_record scsi_buf; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 0bcd5806bd9a..62b1b4a03ee3 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -76,9 +76,9 @@ static void zfcp_erp_action_ready(struct zfcp_erp_action *act) struct zfcp_adapter *adapter = act->adapter; list_move(&act->list, &act->adapter->erp_ready_head); - zfcp_dbf_rec_action("erardy1", act); + zfcp_dbf_rec_run("erardy1", act); wake_up(&adapter->erp_ready_wq); - zfcp_dbf_rec_thread("erardy2", adapter->dbf); + zfcp_dbf_rec_run("erardy2", act); } static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) @@ -239,7 +239,7 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, char *id, void *ref, u32 act_status) { int retval = 1, need; - struct zfcp_erp_action *act = NULL; + struct zfcp_erp_action *act; if (!adapter->erp_thread) return -EIO; @@ -255,10 +255,9 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, ++adapter->erp_total_count; list_add_tail(&act->list, &adapter->erp_ready_head); wake_up(&adapter->erp_ready_wq); - zfcp_dbf_rec_thread("eracte1", adapter->dbf); retval = 0; out: - zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, sdev); + zfcp_dbf_rec_trig(id, adapter, port, sdev, want, need); return retval; } @@ -490,14 +489,14 @@ static int status_change_set(unsigned long mask, atomic_t *status) static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) { if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) - zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf); + zfcp_dbf_rec_run("eraubl1", &adapter->erp_action); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); } static void zfcp_erp_port_unblock(struct zfcp_port *port) { if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) - zfcp_dbf_rec_port("erpubl1", NULL, port); + zfcp_dbf_rec_run("erpubl1", &port->erp_action); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); } @@ -506,14 +505,14 @@ static void zfcp_erp_lun_unblock(struct scsi_device *sdev) struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status)) - zfcp_dbf_rec_lun("erlubl1", NULL, sdev); + zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status); } static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) { list_move(&erp_action->list, &erp_action->adapter->erp_running_head); - zfcp_dbf_rec_action("erator1", erp_action); + zfcp_dbf_rec_run("erator1", erp_action); } static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) @@ -530,11 +529,11 @@ static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) if (act->status & (ZFCP_STATUS_ERP_DISMISSED | ZFCP_STATUS_ERP_TIMEDOUT)) { req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; - zfcp_dbf_rec_action("erscf_1", act); + zfcp_dbf_rec_run("erscf_1", act); req->erp_action = NULL; } if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) - zfcp_dbf_rec_action("erscf_2", act); + zfcp_dbf_rec_run("erscf_2", act); if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) act->fsf_req_id = 0; } else @@ -693,10 +692,8 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) return ZFCP_ERP_FAILED; } - zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf); wait_event(adapter->erp_ready_wq, !list_empty(&adapter->erp_ready_head)); - zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf); if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) break; @@ -735,10 +732,10 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act) if (ret) return ZFCP_ERP_FAILED; - zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf); + zfcp_dbf_rec_run("erasox1", act); wait_event(adapter->erp_ready_wq, !list_empty(&adapter->erp_ready_head)); - zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf); + zfcp_dbf_rec_run("erasox2", act); if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) return ZFCP_ERP_FAILED; @@ -1206,7 +1203,7 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) } list_del(&erp_action->list); - zfcp_dbf_rec_action("eractd1", erp_action); + zfcp_dbf_rec_run("eractd1", erp_action); switch (erp_action->action) { case ZFCP_ERP_ACTION_REOPEN_LUN: @@ -1357,11 +1354,9 @@ static int zfcp_erp_thread(void *data) unsigned long flags; for (;;) { - zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf); wait_event_interruptible(adapter->erp_ready_wq, !list_empty(&adapter->erp_ready_head) || kthread_should_stop()); - zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf); if (kthread_should_stop()) break; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index bf8f3e514839..2d6ee75dfe34 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -46,15 +46,9 @@ extern void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *); /* zfcp_dbf.c */ extern int zfcp_dbf_adapter_register(struct zfcp_adapter *); extern void zfcp_dbf_adapter_unregister(struct zfcp_dbf *); -extern void zfcp_dbf_rec_thread(char *, struct zfcp_dbf *); -extern void zfcp_dbf_rec_thread_lock(char *, struct zfcp_dbf *); -extern void zfcp_dbf_rec_adapter(char *, void *, struct zfcp_dbf *); -extern void zfcp_dbf_rec_port(char *, void *, struct zfcp_port *); -extern void zfcp_dbf_rec_lun(char *, void *, struct scsi_device *); -extern void zfcp_dbf_rec_trigger(char *, void *, u8, u8, void *, - struct zfcp_adapter *, struct zfcp_port *, - struct scsi_device *); -extern void zfcp_dbf_rec_action(char *, struct zfcp_erp_action *); +extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *, + struct zfcp_port *, struct scsi_device *, u8, u8); +extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *); extern void _zfcp_dbf_hba_fsf_response(const char *, int, struct zfcp_fsf_req *, struct zfcp_dbf *); extern void _zfcp_dbf_hba_fsf_unsol(const char *, int level, struct zfcp_dbf *, -- cgit v1.2.3 From 2c55b750a884b86dea8b4cc5f15e1484cc47a25c Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Thu, 2 Dec 2010 15:16:13 +0100 Subject: [SCSI] zfcp: Redesign of the debug tracing for SAN records. This patch is the continuation to redesign the zfcp tracing to a more straight-forward and easy to extend scheme. This patch deals with all trace records of the zfcp SAN area. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 201 +++++++++++-------------------------------- drivers/s390/scsi/zfcp_dbf.h | 68 +++++++-------- drivers/s390/scsi/zfcp_ext.h | 8 +- drivers/s390/scsi/zfcp_fc.c | 2 +- drivers/s390/scsi/zfcp_fsf.c | 8 +- 5 files changed, 85 insertions(+), 202 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 675503628cc9..6ece47e5148c 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -527,183 +527,79 @@ void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp) spin_unlock_irqrestore(&dbf->rec_lock, flags); } -/** - * zfcp_dbf_san_ct_request - trace event for issued CT request - * @fsf_req: request containing issued CT data - * @d_id: destination id where ct request is sent to - */ -void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req, u32 d_id) -{ - struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data; - struct zfcp_adapter *adapter = fsf_req->adapter; - struct zfcp_dbf *dbf = adapter->dbf; - struct fc_ct_hdr *hdr = sg_virt(ct->req); - struct zfcp_dbf_san_record *r = &dbf->san_buf; - struct zfcp_dbf_san_record_ct_request *oct = &r->u.ct_req; - int level = 3; - unsigned long flags; - - spin_lock_irqsave(&dbf->san_lock, flags); - memset(r, 0, sizeof(*r)); - strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE); - r->fsf_reqid = fsf_req->req_id; - r->fsf_seqno = fsf_req->seq_no; - oct->d_id = d_id; - oct->cmd_req_code = hdr->ct_cmd; - oct->revision = hdr->ct_rev; - oct->gs_type = hdr->ct_fs_type; - oct->gs_subtype = hdr->ct_fs_subtype; - oct->options = hdr->ct_options; - oct->max_res_size = hdr->ct_mr_size; - oct->len = min((int)ct->req->length - (int)sizeof(struct fc_ct_hdr), - ZFCP_DBF_SAN_MAX_PAYLOAD); - debug_event(dbf->san, level, r, sizeof(*r)); - zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level, - (void *)hdr + sizeof(struct fc_ct_hdr), oct->len); - spin_unlock_irqrestore(&dbf->san_lock, flags); -} - -/** - * zfcp_dbf_san_ct_response - trace event for completion of CT request - * @fsf_req: request containing CT response - */ -void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req) +static inline +void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf, void *data, u8 id, u16 len, + u64 req_id, u32 d_id) { - struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data; - struct zfcp_adapter *adapter = fsf_req->adapter; - struct fc_ct_hdr *hdr = sg_virt(ct->resp); - struct zfcp_dbf *dbf = adapter->dbf; - struct zfcp_dbf_san_record *r = &dbf->san_buf; - struct zfcp_dbf_san_record_ct_response *rct = &r->u.ct_resp; - int level = 3; + struct zfcp_dbf_san *rec = &dbf->san_buf; + u16 rec_len; unsigned long flags; spin_lock_irqsave(&dbf->san_lock, flags); - memset(r, 0, sizeof(*r)); - strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE); - r->fsf_reqid = fsf_req->req_id; - r->fsf_seqno = fsf_req->seq_no; - rct->cmd_rsp_code = hdr->ct_cmd; - rct->revision = hdr->ct_rev; - rct->reason_code = hdr->ct_reason; - rct->expl = hdr->ct_explan; - rct->vendor_unique = hdr->ct_vendor; - rct->max_res_size = hdr->ct_mr_size; - rct->len = min((int)ct->resp->length - (int)sizeof(struct fc_ct_hdr), - ZFCP_DBF_SAN_MAX_PAYLOAD); - debug_event(dbf->san, level, r, sizeof(*r)); - zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level, - (void *)hdr + sizeof(struct fc_ct_hdr), rct->len); - spin_unlock_irqrestore(&dbf->san_lock, flags); -} + memset(rec, 0, sizeof(*rec)); -static void zfcp_dbf_san_els(const char *tag, int level, - struct zfcp_fsf_req *fsf_req, u32 d_id, - void *buffer, int buflen) -{ - struct zfcp_adapter *adapter = fsf_req->adapter; - struct zfcp_dbf *dbf = adapter->dbf; - struct zfcp_dbf_san_record *rec = &dbf->san_buf; - unsigned long flags; + rec->id = id; + rec->fsf_req_id = req_id; + rec->d_id = d_id; + rec_len = min(len, (u16)ZFCP_DBF_SAN_MAX_PAYLOAD); + memcpy(rec->payload, data, rec_len); + memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); - spin_lock_irqsave(&dbf->san_lock, flags); - memset(rec, 0, sizeof(*rec)); - strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); - rec->fsf_reqid = fsf_req->req_id; - rec->fsf_seqno = fsf_req->seq_no; - rec->u.els.d_id = d_id; - debug_event(dbf->san, level, rec, sizeof(*rec)); - zfcp_dbf_hexdump(dbf->san, rec, sizeof(*rec), level, - buffer, min(buflen, ZFCP_DBF_SAN_MAX_PAYLOAD)); + debug_event(dbf->san, 1, rec, sizeof(*rec)); spin_unlock_irqrestore(&dbf->san_lock, flags); } /** - * zfcp_dbf_san_els_request - trace event for issued ELS - * @fsf_req: request containing issued ELS + * zfcp_dbf_san_req - trace event for issued SAN request + * @tag: indentifier for event + * @fsf_req: request containing issued CT data + * d_id: destination ID */ -void zfcp_dbf_san_els_request(struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_san_req(char *tag, struct zfcp_fsf_req *fsf, u32 d_id) { - struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data; - u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id); + struct zfcp_dbf *dbf = fsf->adapter->dbf; + struct zfcp_fsf_ct_els *ct_els = fsf->data; + u16 length; - zfcp_dbf_san_els("oels", 2, fsf_req, d_id, - sg_virt(els->req), els->req->length); + length = (u16)(ct_els->req->length + FC_CT_HDR_LEN); + zfcp_dbf_san(tag, dbf, sg_virt(ct_els->req), ZFCP_DBF_SAN_REQ, length, + fsf->req_id, d_id); } /** - * zfcp_dbf_san_els_response - trace event for completed ELS - * @fsf_req: request containing ELS response + * zfcp_dbf_san_res - trace event for received SAN request + * @tag: indentifier for event + * @fsf_req: request containing issued CT data */ -void zfcp_dbf_san_els_response(struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_san_res(char *tag, struct zfcp_fsf_req *fsf) { - struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data; - u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id); + struct zfcp_dbf *dbf = fsf->adapter->dbf; + struct zfcp_fsf_ct_els *ct_els = fsf->data; + u16 length; - zfcp_dbf_san_els("rels", 2, fsf_req, d_id, - sg_virt(els->resp), els->resp->length); + length = (u16)(ct_els->resp->length + FC_CT_HDR_LEN); + zfcp_dbf_san(tag, dbf, sg_virt(ct_els->resp), ZFCP_DBF_SAN_RES, length, + fsf->req_id, 0); } /** - * zfcp_dbf_san_incoming_els - trace event for incomig ELS - * @fsf_req: request containing unsolicited status buffer with incoming ELS + * zfcp_dbf_san_in_els - trace event for incoming ELS + * @tag: indentifier for event + * @fsf_req: request containing issued CT data */ -void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *fsf_req) -{ - struct fsf_status_read_buffer *buf = - (struct fsf_status_read_buffer *)fsf_req->data; - int length = (int)buf->length - - (int)((void *)&buf->payload - (void *)buf); - - zfcp_dbf_san_els("iels", 1, fsf_req, ntoh24(buf->d_id), - (void *)buf->payload.data, length); -} - -static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view, - char *out_buf, const char *in_buf) +void zfcp_dbf_san_in_els(char *tag, struct zfcp_fsf_req *fsf) { - struct zfcp_dbf_san_record *r = (struct zfcp_dbf_san_record *)in_buf; - char *p = out_buf; - - if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) - return 0; - - zfcp_dbf_tag(&p, "tag", r->tag); - zfcp_dbf_out(&p, "fsf_reqid", "0x%0Lx", r->fsf_reqid); - zfcp_dbf_out(&p, "fsf_seqno", "0x%08x", r->fsf_seqno); - - if (strncmp(r->tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) { - struct zfcp_dbf_san_record_ct_request *ct = &r->u.ct_req; - zfcp_dbf_out(&p, "d_id", "0x%06x", ct->d_id); - zfcp_dbf_out(&p, "cmd_req_code", "0x%04x", ct->cmd_req_code); - zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision); - zfcp_dbf_out(&p, "gs_type", "0x%02x", ct->gs_type); - zfcp_dbf_out(&p, "gs_subtype", "0x%02x", ct->gs_subtype); - zfcp_dbf_out(&p, "options", "0x%02x", ct->options); - zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size); - } else if (strncmp(r->tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) { - struct zfcp_dbf_san_record_ct_response *ct = &r->u.ct_resp; - zfcp_dbf_out(&p, "cmd_rsp_code", "0x%04x", ct->cmd_rsp_code); - zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision); - zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code); - zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl); - zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique); - zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size); - } else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 || - strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 || - strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) { - struct zfcp_dbf_san_record_els *els = &r->u.els; - zfcp_dbf_out(&p, "d_id", "0x%06x", els->d_id); - } - return p - out_buf; + struct zfcp_dbf *dbf = fsf->adapter->dbf; + struct fsf_status_read_buffer *srb = + (struct fsf_status_read_buffer *) fsf->data; + u16 length; + + length = (u16)(srb->length - + offsetof(struct fsf_status_read_buffer, payload)); + zfcp_dbf_san(tag, dbf, srb->payload.data, ZFCP_DBF_SAN_ELS, length, + fsf->req_id, ntoh24(srb->d_id)); } -static struct debug_view zfcp_dbf_san_view = { - .name = "structured", - .header_proc = zfcp_dbf_view_header, - .format_proc = zfcp_dbf_san_view_format, -}; - void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level, struct zfcp_dbf *dbf, struct scsi_cmnd *scsi_cmnd, struct zfcp_fsf_req *fsf_req, unsigned long old_req_id) @@ -882,8 +778,7 @@ int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter) /* debug feature area which records SAN command failures and recovery */ sprintf(dbf_name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev)); - dbf->san = zfcp_dbf_reg(dbf_name, 6, &zfcp_dbf_san_view, - sizeof(struct zfcp_dbf_san_record)); + dbf->san = zfcp_dbf_reg(dbf_name, 3, NULL, sizeof(struct zfcp_dbf_san)); if (!dbf->san) goto err_out; diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 2e823d4ede6e..a3af6bd3d5aa 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -108,6 +108,34 @@ struct zfcp_dbf_rec { } u; } __packed; +/** + * enum zfcp_dbf_san_id - SAN trace record identifier + * @ZFCP_DBF_SAN_REQ: request trace record id + * @ZFCP_DBF_SAN_RES: response trace record id + * @ZFCP_DBF_SAN_ELS: extended link service record id + */ +enum zfcp_dbf_san_id { + ZFCP_DBF_SAN_REQ = 1, + ZFCP_DBF_SAN_RES = 2, + ZFCP_DBF_SAN_ELS = 3, +}; + +/** struct zfcp_dbf_san - trace record for SAN requests and responses + * @id: unique number of recovery record type + * @tag: identifier string specifying the location of initiation + * @fsf_req_id: request id for fsf requests + * @payload: unformatted information related to request/response + * @d_id: destination id + */ +struct zfcp_dbf_san { + u8 id; + char tag[ZFCP_DBF_TAG_LEN]; + u64 fsf_req_id; + u32 d_id; +#define ZFCP_DBF_SAN_MAX_PAYLOAD (FC_CT_HDR_LEN + 32) + char payload[ZFCP_DBF_SAN_MAX_PAYLOAD]; +} __packed; + struct zfcp_dbf_hba_record_response { u32 fsf_command; u64 fsf_reqid; @@ -176,44 +204,6 @@ struct zfcp_dbf_hba_record { } u; } __attribute__ ((packed)); -struct zfcp_dbf_san_record_ct_request { - u16 cmd_req_code; - u8 revision; - u8 gs_type; - u8 gs_subtype; - u8 options; - u16 max_res_size; - u32 len; - u32 d_id; -} __attribute__ ((packed)); - -struct zfcp_dbf_san_record_ct_response { - u16 cmd_rsp_code; - u8 revision; - u8 reason_code; - u8 expl; - u8 vendor_unique; - u16 max_res_size; - u32 len; -} __attribute__ ((packed)); - -struct zfcp_dbf_san_record_els { - u32 d_id; -} __attribute__ ((packed)); - -struct zfcp_dbf_san_record { - u8 tag[ZFCP_DBF_TAG_SIZE]; - u64 fsf_reqid; - u32 fsf_seqno; - union { - struct zfcp_dbf_san_record_ct_request ct_req; - struct zfcp_dbf_san_record_ct_response ct_resp; - struct zfcp_dbf_san_record_els els; - } u; -} __attribute__ ((packed)); - -#define ZFCP_DBF_SAN_MAX_PAYLOAD 1024 - struct zfcp_dbf_scsi_record { u8 tag[ZFCP_DBF_TAG_SIZE]; u8 tag2[ZFCP_DBF_TAG_SIZE]; @@ -250,7 +240,7 @@ struct zfcp_dbf { spinlock_t scsi_lock; struct zfcp_dbf_rec rec_buf; struct zfcp_dbf_hba_record hba_buf; - struct zfcp_dbf_san_record san_buf; + struct zfcp_dbf_san san_buf; struct zfcp_dbf_scsi_record scsi_buf; struct zfcp_adapter *adapter; }; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 2d6ee75dfe34..ff7effe55379 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -55,11 +55,9 @@ extern void _zfcp_dbf_hba_fsf_unsol(const char *, int level, struct zfcp_dbf *, struct fsf_status_read_buffer *); extern void zfcp_dbf_hba_qdio(struct zfcp_dbf *, unsigned int, int, int); extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *); -extern void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *, u32); -extern void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *); -extern void zfcp_dbf_san_els_request(struct zfcp_fsf_req *); -extern void zfcp_dbf_san_els_response(struct zfcp_fsf_req *); -extern void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *); +extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32); +extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); +extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *); extern void _zfcp_dbf_scsi(const char *, const char *, int, struct zfcp_dbf *, struct scsi_cmnd *, struct zfcp_fsf_req *, unsigned long); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 86fd905df48b..7d44d9c59bdc 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -251,7 +251,7 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req) (struct fsf_status_read_buffer *) fsf_req->data; unsigned int els_type = status_buffer->payload.data[0]; - zfcp_dbf_san_incoming_els(fsf_req); + zfcp_dbf_san_in_els("fciels1", fsf_req); if (els_type == ELS_PLOGI) zfcp_fc_incoming_plogi(fsf_req); else if (els_type == ELS_LOGO) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 2eb7dd56ab80..6d805c50627f 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -882,7 +882,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_GOOD: - zfcp_dbf_san_ct_response(req); + zfcp_dbf_san_res("fsscth1", req); ct->status = 0; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: @@ -1025,7 +1025,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, req->qtcb->header.port_handle = wka_port->handle; req->data = ct; - zfcp_dbf_san_ct_request(req, wka_port->d_id); + zfcp_dbf_san_req("fssct_1", req, wka_port->d_id); ret = zfcp_fsf_req_send(req); if (ret) @@ -1053,7 +1053,7 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_GOOD: - zfcp_dbf_san_els_response(req); + zfcp_dbf_san_res("fsselh1", req); send_els->status = 0; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: @@ -1127,7 +1127,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, req->handler = zfcp_fsf_send_els_handler; req->data = els; - zfcp_dbf_san_els_request(req); + zfcp_dbf_san_req("fssels1", req, d_id); ret = zfcp_fsf_req_send(req); if (ret) -- cgit v1.2.3 From a54ca0f62f953898b05549391ac2a8a4dad6482b Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Thu, 2 Dec 2010 15:16:14 +0100 Subject: [SCSI] zfcp: Redesign of the debug tracing for HBA records. This patch is the continuation to redesign the zfcp tracing to a more straight-forward and easy to extend scheme. This patch deals with all trace records of the zfcp HBA area. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 433 ++++++++++++------------------------------ drivers/s390/scsi/zfcp_dbf.h | 197 +++++++++---------- drivers/s390/scsi/zfcp_ext.h | 10 +- drivers/s390/scsi/zfcp_fsf.c | 18 +- drivers/s390/scsi/zfcp_qdio.c | 2 - 5 files changed, 229 insertions(+), 431 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 6ece47e5148c..b57a47b64b80 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -22,22 +22,34 @@ module_param(dbfsize, uint, 0400); MODULE_PARM_DESC(dbfsize, "number of pages for each debug feature area (default 4)"); -static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len, - int level, char *from, int from_len) +static inline unsigned int zfcp_dbf_plen(unsigned int offset) { - int offset; - struct zfcp_dbf_dump *dump = to; - int room = to_len - sizeof(*dump); - - for (offset = 0; offset < from_len; offset += dump->size) { - memset(to, 0, to_len); - strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE); - dump->total_size = from_len; - dump->offset = offset; - dump->size = min(from_len - offset, room); - memcpy(dump->data, from + offset, dump->size); - debug_event(dbf, level, dump, dump->size + sizeof(*dump)); + return sizeof(struct zfcp_dbf_pay) + offset - ZFCP_DBF_PAY_MAX_REC; +} + +static inline +void zfcp_dbf_pl_write(struct zfcp_dbf *dbf, void *data, u16 length, char *area, + u64 req_id) +{ + struct zfcp_dbf_pay *pl = &dbf->pay_buf; + u16 offset = 0, rec_length; + + spin_lock(&dbf->pay_lock); + memset(pl, 0, sizeof(*pl)); + pl->fsf_req_id = req_id; + memcpy(pl->area, area, ZFCP_DBF_TAG_LEN); + + while (offset < length) { + rec_length = min((u16) ZFCP_DBF_PAY_MAX_REC, + (u16) (length - offset)); + memcpy(pl->data, data + offset, rec_length); + debug_event(dbf->pay, 1, pl, zfcp_dbf_plen(rec_length)); + + offset += rec_length; + pl->counter++; } + + spin_unlock(&dbf->pay_lock); } static void zfcp_dbf_tag(char **p, const char *label, const char *tag) @@ -104,336 +116,117 @@ static int zfcp_dbf_view_header(debug_info_t *id, struct debug_view *view, return p - out_buf; } -void _zfcp_dbf_hba_fsf_response(const char *tag2, int level, - struct zfcp_fsf_req *fsf_req, - struct zfcp_dbf *dbf) -{ - struct fsf_qtcb *qtcb = fsf_req->qtcb; - union fsf_prot_status_qual *prot_status_qual = - &qtcb->prefix.prot_status_qual; - union fsf_status_qual *fsf_status_qual = &qtcb->header.fsf_status_qual; - struct scsi_cmnd *scsi_cmnd; - struct zfcp_port *port; - struct zfcp_unit *unit; - struct zfcp_send_els *send_els; - struct zfcp_dbf_hba_record *rec = &dbf->hba_buf; - struct zfcp_dbf_hba_record_response *response = &rec->u.response; - unsigned long flags; - - spin_lock_irqsave(&dbf->hba_lock, flags); - memset(rec, 0, sizeof(*rec)); - strncpy(rec->tag, "resp", ZFCP_DBF_TAG_SIZE); - strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE); - - response->fsf_command = fsf_req->fsf_command; - response->fsf_reqid = fsf_req->req_id; - response->fsf_seqno = fsf_req->seq_no; - response->fsf_issued = fsf_req->issued; - response->fsf_prot_status = qtcb->prefix.prot_status; - response->fsf_status = qtcb->header.fsf_status; - memcpy(response->fsf_prot_status_qual, - prot_status_qual, FSF_PROT_STATUS_QUAL_SIZE); - memcpy(response->fsf_status_qual, - fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE); - response->fsf_req_status = fsf_req->status; - response->sbal_first = fsf_req->qdio_req.sbal_first; - response->sbal_last = fsf_req->qdio_req.sbal_last; - response->sbal_response = fsf_req->qdio_req.sbal_response; - response->pool = fsf_req->pool != NULL; - response->erp_action = (unsigned long)fsf_req->erp_action; - - switch (fsf_req->fsf_command) { - case FSF_QTCB_FCP_CMND: - if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) - break; - scsi_cmnd = (struct scsi_cmnd *)fsf_req->data; - if (scsi_cmnd) { - response->u.fcp.cmnd = (unsigned long)scsi_cmnd; - response->u.fcp.data_dir = - qtcb->bottom.io.data_direction; - } - break; - - case FSF_QTCB_OPEN_PORT_WITH_DID: - case FSF_QTCB_CLOSE_PORT: - case FSF_QTCB_CLOSE_PHYSICAL_PORT: - port = (struct zfcp_port *)fsf_req->data; - response->u.port.wwpn = port->wwpn; - response->u.port.d_id = port->d_id; - response->u.port.port_handle = qtcb->header.port_handle; - break; - - case FSF_QTCB_OPEN_LUN: - case FSF_QTCB_CLOSE_LUN: - unit = (struct zfcp_unit *)fsf_req->data; - port = unit->port; - response->u.unit.wwpn = port->wwpn; - response->u.unit.fcp_lun = unit->fcp_lun; - response->u.unit.port_handle = qtcb->header.port_handle; - response->u.unit.lun_handle = qtcb->header.lun_handle; - break; - - case FSF_QTCB_SEND_ELS: - send_els = (struct zfcp_send_els *)fsf_req->data; - response->u.els.d_id = ntoh24(qtcb->bottom.support.d_id); - break; - - case FSF_QTCB_ABORT_FCP_CMND: - case FSF_QTCB_SEND_GENERIC: - case FSF_QTCB_EXCHANGE_CONFIG_DATA: - case FSF_QTCB_EXCHANGE_PORT_DATA: - case FSF_QTCB_DOWNLOAD_CONTROL_FILE: - case FSF_QTCB_UPLOAD_CONTROL_FILE: - break; - } - - debug_event(dbf->hba, level, rec, sizeof(*rec)); - - /* have fcp channel microcode fixed to use as little as possible */ - if (fsf_req->fsf_command != FSF_QTCB_FCP_CMND) { - /* adjust length skipping trailing zeros */ - char *buf = (char *)qtcb + qtcb->header.log_start; - int len = qtcb->header.log_length; - for (; len && !buf[len - 1]; len--); - zfcp_dbf_hexdump(dbf->hba, rec, sizeof(*rec), level, buf, - len); - } - - spin_unlock_irqrestore(&dbf->hba_lock, flags); -} - -void _zfcp_dbf_hba_fsf_unsol(const char *tag, int level, struct zfcp_dbf *dbf, - struct fsf_status_read_buffer *status_buffer) +/** + * zfcp_dbf_hba_fsf_res - trace event for fsf responses + * @tag: tag indicating which kind of unsolicited status has been received + * @req: request for which a response was received + */ +void zfcp_dbf_hba_fsf_res(char *tag, struct zfcp_fsf_req *req) { - struct zfcp_dbf_hba_record *rec = &dbf->hba_buf; + struct zfcp_dbf *dbf = req->adapter->dbf; + struct fsf_qtcb_prefix *q_pref = &req->qtcb->prefix; + struct fsf_qtcb_header *q_head = &req->qtcb->header; + struct zfcp_dbf_hba *rec = &dbf->hba_buf; unsigned long flags; spin_lock_irqsave(&dbf->hba_lock, flags); memset(rec, 0, sizeof(*rec)); - strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); - strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); - - rec->u.status.failed = atomic_read(&dbf->adapter->stat_miss); - if (status_buffer != NULL) { - rec->u.status.status_type = status_buffer->status_type; - rec->u.status.status_subtype = status_buffer->status_subtype; - memcpy(&rec->u.status.queue_designator, - &status_buffer->queue_designator, - sizeof(struct fsf_queue_designator)); - - switch (status_buffer->status_type) { - case FSF_STATUS_READ_SENSE_DATA_AVAIL: - rec->u.status.payload_size = - ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL; - break; - case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: - rec->u.status.payload_size = - ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD; - break; - - case FSF_STATUS_READ_LINK_DOWN: - switch (status_buffer->status_subtype) { - case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: - case FSF_STATUS_READ_SUB_FDISC_FAILED: - rec->u.status.payload_size = - sizeof(struct fsf_link_down_info); - } - break; - - case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: - rec->u.status.payload_size = - ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT; - break; - } - memcpy(&rec->u.status.payload, - &status_buffer->payload, rec->u.status.payload_size); + memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); + rec->id = ZFCP_DBF_HBA_RES; + rec->fsf_req_id = req->req_id; + rec->fsf_req_status = req->status; + rec->fsf_cmd = req->fsf_command; + rec->fsf_seq_no = req->seq_no; + rec->u.res.req_issued = req->issued; + rec->u.res.prot_status = q_pref->prot_status; + rec->u.res.fsf_status = q_head->fsf_status; + + memcpy(rec->u.res.prot_status_qual, &q_pref->prot_status_qual, + FSF_PROT_STATUS_QUAL_SIZE); + memcpy(rec->u.res.fsf_status_qual, &q_head->fsf_status_qual, + FSF_STATUS_QUALIFIER_SIZE); + + if (req->fsf_command != FSF_QTCB_FCP_CMND) { + rec->pl_len = q_head->log_length; + zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start, + rec->pl_len, "fsf_res", req->req_id); } - debug_event(dbf->hba, level, rec, sizeof(*rec)); + debug_event(dbf->hba, 1, rec, sizeof(*rec)); spin_unlock_irqrestore(&dbf->hba_lock, flags); } /** - * zfcp_dbf_hba_qdio - trace event for QDIO related failure - * @qdio: qdio structure affected by this QDIO related event - * @qdio_error: as passed by qdio module - * @sbal_index: first buffer with error condition, as passed by qdio module - * @sbal_count: number of buffers affected, as passed by qdio module + * zfcp_dbf_hba_fsf_uss - trace event for an unsolicited status buffer + * @tag: tag indicating which kind of unsolicited status has been received + * @req: request providing the unsolicited status */ -void zfcp_dbf_hba_qdio(struct zfcp_dbf *dbf, unsigned int qdio_error, - int sbal_index, int sbal_count) +void zfcp_dbf_hba_fsf_uss(char *tag, struct zfcp_fsf_req *req) { - struct zfcp_dbf_hba_record *r = &dbf->hba_buf; + struct zfcp_dbf *dbf = req->adapter->dbf; + struct fsf_status_read_buffer *srb = req->data; + struct zfcp_dbf_hba *rec = &dbf->hba_buf; unsigned long flags; spin_lock_irqsave(&dbf->hba_lock, flags); - memset(r, 0, sizeof(*r)); - strncpy(r->tag, "qdio", ZFCP_DBF_TAG_SIZE); - r->u.qdio.qdio_error = qdio_error; - r->u.qdio.sbal_index = sbal_index; - r->u.qdio.sbal_count = sbal_count; - debug_event(dbf->hba, 0, r, sizeof(*r)); + memset(rec, 0, sizeof(*rec)); + + memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); + rec->id = ZFCP_DBF_HBA_USS; + rec->fsf_req_id = req->req_id; + rec->fsf_req_status = req->status; + rec->fsf_cmd = req->fsf_command; + + if (!srb) + goto log; + + rec->u.uss.status_type = srb->status_type; + rec->u.uss.status_subtype = srb->status_subtype; + rec->u.uss.d_id = ntoh24(srb->d_id); + rec->u.uss.lun = srb->fcp_lun; + memcpy(&rec->u.uss.queue_designator, &srb->queue_designator, + sizeof(rec->u.uss.queue_designator)); + + /* status read buffer payload length */ + rec->pl_len = (!srb->length) ? 0 : srb->length - + offsetof(struct fsf_status_read_buffer, payload); + + if (rec->pl_len) + zfcp_dbf_pl_write(dbf, srb->payload.data, rec->pl_len, + "fsf_uss", req->req_id); +log: + debug_event(dbf->hba, 2, rec, sizeof(*rec)); spin_unlock_irqrestore(&dbf->hba_lock, flags); } /** - * zfcp_dbf_hba_berr - trace event for bit error threshold - * @dbf: dbf structure affected by this QDIO related event - * @req: fsf request + * zfcp_dbf_hba_bit_err - trace event for bit error conditions + * @tag: tag indicating which kind of unsolicited status has been received + * @req: request which caused the bit_error condition */ -void zfcp_dbf_hba_berr(struct zfcp_dbf *dbf, struct zfcp_fsf_req *req) +void zfcp_dbf_hba_bit_err(char *tag, struct zfcp_fsf_req *req) { - struct zfcp_dbf_hba_record *r = &dbf->hba_buf; + struct zfcp_dbf *dbf = req->adapter->dbf; + struct zfcp_dbf_hba *rec = &dbf->hba_buf; struct fsf_status_read_buffer *sr_buf = req->data; - struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error; unsigned long flags; spin_lock_irqsave(&dbf->hba_lock, flags); - memset(r, 0, sizeof(*r)); - strncpy(r->tag, "berr", ZFCP_DBF_TAG_SIZE); - memcpy(&r->u.berr, err, sizeof(struct fsf_bit_error_payload)); - debug_event(dbf->hba, 0, r, sizeof(*r)); - spin_unlock_irqrestore(&dbf->hba_lock, flags); -} -static void zfcp_dbf_hba_view_response(char **p, - struct zfcp_dbf_hba_record_response *r) -{ - struct timespec t; - - zfcp_dbf_out(p, "fsf_command", "0x%08x", r->fsf_command); - zfcp_dbf_out(p, "fsf_reqid", "0x%0Lx", r->fsf_reqid); - zfcp_dbf_out(p, "fsf_seqno", "0x%08x", r->fsf_seqno); - stck_to_timespec(r->fsf_issued, &t); - zfcp_dbf_out(p, "fsf_issued", "%011lu:%06lu", t.tv_sec, t.tv_nsec); - zfcp_dbf_out(p, "fsf_prot_status", "0x%08x", r->fsf_prot_status); - zfcp_dbf_out(p, "fsf_status", "0x%08x", r->fsf_status); - zfcp_dbf_outd(p, "fsf_prot_status_qual", r->fsf_prot_status_qual, - FSF_PROT_STATUS_QUAL_SIZE, 0, FSF_PROT_STATUS_QUAL_SIZE); - zfcp_dbf_outd(p, "fsf_status_qual", r->fsf_status_qual, - FSF_STATUS_QUALIFIER_SIZE, 0, FSF_STATUS_QUALIFIER_SIZE); - zfcp_dbf_out(p, "fsf_req_status", "0x%08x", r->fsf_req_status); - zfcp_dbf_out(p, "sbal_first", "0x%02x", r->sbal_first); - zfcp_dbf_out(p, "sbal_last", "0x%02x", r->sbal_last); - zfcp_dbf_out(p, "sbal_response", "0x%02x", r->sbal_response); - zfcp_dbf_out(p, "pool", "0x%02x", r->pool); - - switch (r->fsf_command) { - case FSF_QTCB_FCP_CMND: - if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) - break; - zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir); - zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd); - *p += sprintf(*p, "\n"); - break; - - case FSF_QTCB_OPEN_PORT_WITH_DID: - case FSF_QTCB_CLOSE_PORT: - case FSF_QTCB_CLOSE_PHYSICAL_PORT: - zfcp_dbf_out(p, "wwpn", "0x%016Lx", r->u.port.wwpn); - zfcp_dbf_out(p, "d_id", "0x%06x", r->u.port.d_id); - zfcp_dbf_out(p, "port_handle", "0x%08x", r->u.port.port_handle); - break; - - case FSF_QTCB_OPEN_LUN: - case FSF_QTCB_CLOSE_LUN: - zfcp_dbf_out(p, "wwpn", "0x%016Lx", r->u.unit.wwpn); - zfcp_dbf_out(p, "fcp_lun", "0x%016Lx", r->u.unit.fcp_lun); - zfcp_dbf_out(p, "port_handle", "0x%08x", r->u.unit.port_handle); - zfcp_dbf_out(p, "lun_handle", "0x%08x", r->u.unit.lun_handle); - break; - - case FSF_QTCB_SEND_ELS: - zfcp_dbf_out(p, "d_id", "0x%06x", r->u.els.d_id); - break; - - case FSF_QTCB_ABORT_FCP_CMND: - case FSF_QTCB_SEND_GENERIC: - case FSF_QTCB_EXCHANGE_CONFIG_DATA: - case FSF_QTCB_EXCHANGE_PORT_DATA: - case FSF_QTCB_DOWNLOAD_CONTROL_FILE: - case FSF_QTCB_UPLOAD_CONTROL_FILE: - break; - } -} - -static void zfcp_dbf_hba_view_status(char **p, - struct zfcp_dbf_hba_record_status *r) -{ - zfcp_dbf_out(p, "failed", "0x%02x", r->failed); - zfcp_dbf_out(p, "status_type", "0x%08x", r->status_type); - zfcp_dbf_out(p, "status_subtype", "0x%08x", r->status_subtype); - zfcp_dbf_outd(p, "queue_designator", (char *)&r->queue_designator, - sizeof(struct fsf_queue_designator), 0, - sizeof(struct fsf_queue_designator)); - zfcp_dbf_outd(p, "payload", (char *)&r->payload, r->payload_size, 0, - r->payload_size); -} - -static void zfcp_dbf_hba_view_qdio(char **p, struct zfcp_dbf_hba_record_qdio *r) -{ - zfcp_dbf_out(p, "qdio_error", "0x%08x", r->qdio_error); - zfcp_dbf_out(p, "sbal_index", "0x%02x", r->sbal_index); - zfcp_dbf_out(p, "sbal_count", "0x%02x", r->sbal_count); -} - -static void zfcp_dbf_hba_view_berr(char **p, struct fsf_bit_error_payload *r) -{ - zfcp_dbf_out(p, "link_failures", "%d", r->link_failure_error_count); - zfcp_dbf_out(p, "loss_of_sync_err", "%d", r->loss_of_sync_error_count); - zfcp_dbf_out(p, "loss_of_sig_err", "%d", r->loss_of_signal_error_count); - zfcp_dbf_out(p, "prim_seq_err", "%d", - r->primitive_sequence_error_count); - zfcp_dbf_out(p, "inval_trans_word_err", "%d", - r->invalid_transmission_word_error_count); - zfcp_dbf_out(p, "CRC_errors", "%d", r->crc_error_count); - zfcp_dbf_out(p, "prim_seq_event_to", "%d", - r->primitive_sequence_event_timeout_count); - zfcp_dbf_out(p, "elast_buf_overrun_err", "%d", - r->elastic_buffer_overrun_error_count); - zfcp_dbf_out(p, "adv_rec_buf2buf_cred", "%d", - r->advertised_receive_b2b_credit); - zfcp_dbf_out(p, "curr_rec_buf2buf_cred", "%d", - r->current_receive_b2b_credit); - zfcp_dbf_out(p, "adv_trans_buf2buf_cred", "%d", - r->advertised_transmit_b2b_credit); - zfcp_dbf_out(p, "curr_trans_buf2buf_cred", "%d", - r->current_transmit_b2b_credit); -} - -static int zfcp_dbf_hba_view_format(debug_info_t *id, struct debug_view *view, - char *out_buf, const char *in_buf) -{ - struct zfcp_dbf_hba_record *r = (struct zfcp_dbf_hba_record *)in_buf; - char *p = out_buf; - - if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) - return 0; + memset(rec, 0, sizeof(*rec)); - zfcp_dbf_tag(&p, "tag", r->tag); - if (isalpha(r->tag2[0])) - zfcp_dbf_tag(&p, "tag2", r->tag2); - - if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) == 0) - zfcp_dbf_hba_view_response(&p, &r->u.response); - else if (strncmp(r->tag, "stat", ZFCP_DBF_TAG_SIZE) == 0) - zfcp_dbf_hba_view_status(&p, &r->u.status); - else if (strncmp(r->tag, "qdio", ZFCP_DBF_TAG_SIZE) == 0) - zfcp_dbf_hba_view_qdio(&p, &r->u.qdio); - else if (strncmp(r->tag, "berr", ZFCP_DBF_TAG_SIZE) == 0) - zfcp_dbf_hba_view_berr(&p, &r->u.berr); - - if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) != 0) - p += sprintf(p, "\n"); - return p - out_buf; + memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); + rec->id = ZFCP_DBF_HBA_BIT; + rec->fsf_req_id = req->req_id; + rec->fsf_req_status = req->status; + rec->fsf_cmd = req->fsf_command; + memcpy(&rec->u.be, &sr_buf->payload.bit_error, + sizeof(struct fsf_bit_error_payload)); + + debug_event(dbf->hba, 1, rec, sizeof(*rec)); + spin_unlock_irqrestore(&dbf->hba_lock, flags); } -static struct debug_view zfcp_dbf_hba_view = { - .name = "structured", - .header_proc = zfcp_dbf_view_header, - .format_proc = zfcp_dbf_hba_view_format, -}; - static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec, struct zfcp_adapter *adapter, struct zfcp_port *port, @@ -758,6 +551,7 @@ int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter) dbf->adapter = adapter; + spin_lock_init(&dbf->pay_lock); spin_lock_init(&dbf->hba_lock); spin_lock_init(&dbf->san_lock); spin_lock_init(&dbf->scsi_lock); @@ -771,11 +565,17 @@ int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter) /* debug feature area which records HBA (FSF and QDIO) conditions */ sprintf(dbf_name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev)); - dbf->hba = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_hba_view, - sizeof(struct zfcp_dbf_hba_record)); + dbf->hba = zfcp_dbf_reg(dbf_name, 3, NULL, sizeof(struct zfcp_dbf_hba)); if (!dbf->hba) goto err_out; + /* debug feature area which records payload info */ + sprintf(dbf_name, "zfcp_%s_pay", dev_name(&adapter->ccw_device->dev)); + dbf->pay = zfcp_dbf_reg(dbf_name, 3, NULL, + sizeof(struct zfcp_dbf_pay)); + if (!dbf->pay) + goto err_out; + /* debug feature area which records SAN command failures and recovery */ sprintf(dbf_name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev)); dbf->san = zfcp_dbf_reg(dbf_name, 3, NULL, sizeof(struct zfcp_dbf_san)); @@ -808,6 +608,7 @@ void zfcp_dbf_adapter_unregister(struct zfcp_dbf *dbf) debug_unregister(dbf->scsi); debug_unregister(dbf->san); debug_unregister(dbf->hba); + debug_unregister(dbf->pay); debug_unregister(dbf->rec); dbf->adapter->dbf = NULL; kfree(dbf); diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index a3af6bd3d5aa..5dc0b414cf28 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -1,22 +1,8 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver + * debug feature declarations * - * Copyright IBM Corp. 2008, 2009 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corp. 2008, 2010 */ #ifndef ZFCP_DBF_H @@ -136,73 +122,90 @@ struct zfcp_dbf_san { char payload[ZFCP_DBF_SAN_MAX_PAYLOAD]; } __packed; -struct zfcp_dbf_hba_record_response { - u32 fsf_command; - u64 fsf_reqid; - u32 fsf_seqno; - u64 fsf_issued; - u32 fsf_prot_status; +/** + * struct zfcp_dbf_hba_res - trace record for hba responses + * @req_issued: timestamp when request was issued + * @prot_status: protocol status + * @prot_status_qual: protocol status qualifier + * @fsf_status: fsf status + * @fsf_status_qual: fsf status qualifier + */ +struct zfcp_dbf_hba_res { + u64 req_issued; + u32 prot_status; + u8 prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE]; u32 fsf_status; - u8 fsf_prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE]; - u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; - u32 fsf_req_status; - u8 sbal_first; - u8 sbal_last; - u8 sbal_response; - u8 pool; - u64 erp_action; - union { - struct { - u64 cmnd; - u32 data_dir; - } fcp; - struct { - u64 wwpn; - u32 d_id; - u32 port_handle; - } port; - struct { - u64 wwpn; - u64 fcp_lun; - u32 port_handle; - u32 lun_handle; - } unit; - struct { - u32 d_id; - } els; - } u; -} __attribute__ ((packed)); + u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; +} __packed; -struct zfcp_dbf_hba_record_status { - u8 failed; +/** + * struct zfcp_dbf_hba_uss - trace record for unsolicited status + * @status_type: type of unsolicited status + * @status_subtype: subtype of unsolicited status + * @d_id: destination ID + * @lun: logical unit number + * @queue_designator: queue designator + */ +struct zfcp_dbf_hba_uss { u32 status_type; u32 status_subtype; - struct fsf_queue_designator - queue_designator; - u32 payload_size; -#define ZFCP_DBF_UNSOL_PAYLOAD 80 -#define ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL 32 -#define ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD 56 -#define ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT 2 * sizeof(u32) - u8 payload[ZFCP_DBF_UNSOL_PAYLOAD]; -} __attribute__ ((packed)); + u32 d_id; + u64 lun; + u64 queue_designator; +} __packed; -struct zfcp_dbf_hba_record_qdio { - u32 qdio_error; - u8 sbal_index; - u8 sbal_count; -} __attribute__ ((packed)); +/** + * enum zfcp_dbf_hba_id - HBA trace record identifier + * @ZFCP_DBF_HBA_RES: response trace record + * @ZFCP_DBF_HBA_USS: unsolicited status trace record + * @ZFCP_DBF_HBA_BIT: bit error trace record + */ +enum zfcp_dbf_hba_id { + ZFCP_DBF_HBA_RES = 1, + ZFCP_DBF_HBA_USS = 2, + ZFCP_DBF_HBA_BIT = 3, +}; -struct zfcp_dbf_hba_record { - u8 tag[ZFCP_DBF_TAG_SIZE]; - u8 tag2[ZFCP_DBF_TAG_SIZE]; +/** + * struct zfcp_dbf_hba - common trace record for HBA records + * @id: unique number of recovery record type + * @tag: identifier string specifying the location of initiation + * @fsf_req_id: request id for fsf requests + * @fsf_req_status: status of fsf request + * @fsf_cmd: fsf command + * @fsf_seq_no: fsf sequence number + * @pl_len: length of payload stored as zfcp_dbf_pay + * @u: record type specific data + */ +struct zfcp_dbf_hba { + u8 id; + char tag[ZFCP_DBF_TAG_LEN]; + u64 fsf_req_id; + u32 fsf_req_status; + u32 fsf_cmd; + u32 fsf_seq_no; + u16 pl_len; union { - struct zfcp_dbf_hba_record_response response; - struct zfcp_dbf_hba_record_status status; - struct zfcp_dbf_hba_record_qdio qdio; - struct fsf_bit_error_payload berr; + struct zfcp_dbf_hba_res res; + struct zfcp_dbf_hba_uss uss; + struct fsf_bit_error_payload be; } u; -} __attribute__ ((packed)); +} __packed; + +/** + * struct zfcp_dbf_pay - trace record for unformatted payload information + * @area: area this record is originated from + * @counter: ascending record number + * @fsf_req_id: request id of fsf request + * @data: unformatted data + */ +struct zfcp_dbf_pay { + char area[ZFCP_DBF_TAG_LEN]; + char counter; + u64 fsf_req_id; +#define ZFCP_DBF_PAY_MAX_REC 0x100 + char data[ZFCP_DBF_PAY_MAX_REC]; +} __packed; struct zfcp_dbf_scsi_record { u8 tag[ZFCP_DBF_TAG_SIZE]; @@ -230,71 +233,57 @@ struct zfcp_dbf_scsi_record { } __attribute__ ((packed)); struct zfcp_dbf { + debug_info_t *pay; debug_info_t *rec; debug_info_t *hba; debug_info_t *san; debug_info_t *scsi; + spinlock_t pay_lock; spinlock_t rec_lock; spinlock_t hba_lock; spinlock_t san_lock; spinlock_t scsi_lock; struct zfcp_dbf_rec rec_buf; - struct zfcp_dbf_hba_record hba_buf; + struct zfcp_dbf_hba hba_buf; struct zfcp_dbf_san san_buf; struct zfcp_dbf_scsi_record scsi_buf; + struct zfcp_dbf_pay pay_buf; struct zfcp_adapter *adapter; }; static inline -void zfcp_dbf_hba_fsf_resp(const char *tag2, int level, - struct zfcp_fsf_req *req, struct zfcp_dbf *dbf) +void zfcp_dbf_hba_fsf_resp(char *tag, int level, struct zfcp_fsf_req *req) { - if (level <= dbf->hba->level) - _zfcp_dbf_hba_fsf_response(tag2, level, req, dbf); + if (level <= req->adapter->dbf->hba->level) + zfcp_dbf_hba_fsf_res(tag, req); } /** * zfcp_dbf_hba_fsf_response - trace event for request completion * @fsf_req: request that has been completed */ -static inline void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req) +static inline +void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req) { - struct zfcp_dbf *dbf = req->adapter->dbf; struct fsf_qtcb *qtcb = req->qtcb; if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) && (qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { - zfcp_dbf_hba_fsf_resp("perr", 1, req, dbf); + zfcp_dbf_hba_fsf_resp("fs_perr", 1, req); } else if (qtcb->header.fsf_status != FSF_GOOD) { - zfcp_dbf_hba_fsf_resp("ferr", 1, req, dbf); + zfcp_dbf_hba_fsf_resp("fs_ferr", 1, req); } else if ((req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) || (req->fsf_command == FSF_QTCB_OPEN_LUN)) { - zfcp_dbf_hba_fsf_resp("open", 4, req, dbf); + zfcp_dbf_hba_fsf_resp("fs_open", 4, req); } else if (qtcb->header.log_length) { - zfcp_dbf_hba_fsf_resp("qtcb", 5, req, dbf); + zfcp_dbf_hba_fsf_resp("fs_qtcb", 5, req); } else { - zfcp_dbf_hba_fsf_resp("norm", 6, req, dbf); + zfcp_dbf_hba_fsf_resp("fs_norm", 6, req); } - } - -/** - * zfcp_dbf_hba_fsf_unsol - trace event for an unsolicited status buffer - * @tag: tag indicating which kind of unsolicited status has been received - * @dbf: reference to dbf structure - * @status_buffer: buffer containing payload of unsolicited status - */ -static inline -void zfcp_dbf_hba_fsf_unsol(const char *tag, struct zfcp_dbf *dbf, - struct fsf_status_read_buffer *buf) -{ - int level = 2; - - if (level <= dbf->hba->level) - _zfcp_dbf_hba_fsf_unsol(tag, level, dbf, buf); } static inline diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index ff7effe55379..00875de2cb99 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -49,11 +49,9 @@ extern void zfcp_dbf_adapter_unregister(struct zfcp_dbf *); extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *, struct zfcp_port *, struct scsi_device *, u8, u8); extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *); -extern void _zfcp_dbf_hba_fsf_response(const char *, int, struct zfcp_fsf_req *, - struct zfcp_dbf *); -extern void _zfcp_dbf_hba_fsf_unsol(const char *, int level, struct zfcp_dbf *, - struct fsf_status_read_buffer *); -extern void zfcp_dbf_hba_qdio(struct zfcp_dbf *, unsigned int, int, int); +extern void zfcp_dbf_hba_fsf_uss(char *, struct zfcp_fsf_req *); +extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *); +extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *); extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *); extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32); extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); @@ -141,6 +139,8 @@ extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *, extern int zfcp_qdio_open(struct zfcp_qdio *); extern void zfcp_qdio_close(struct zfcp_qdio *); extern void zfcp_qdio_siosl(struct zfcp_adapter *); +extern struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *, + struct qdio_buffer *); /* zfcp_scsi.c */ extern struct zfcp_data zfcp_data; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 6d805c50627f..9881ba947f11 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -211,13 +211,13 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) struct fsf_status_read_buffer *sr_buf = req->data; if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { - zfcp_dbf_hba_fsf_unsol("dism", adapter->dbf, sr_buf); + zfcp_dbf_hba_fsf_uss("fssrh_1", req); mempool_free(sr_buf, adapter->pool.status_read_data); zfcp_fsf_req_free(req); return; } - zfcp_dbf_hba_fsf_unsol("read", adapter->dbf, sr_buf); + zfcp_dbf_hba_fsf_uss("fssrh_2", req); switch (sr_buf->status_type) { case FSF_STATUS_READ_PORT_CLOSED: @@ -232,7 +232,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) dev_warn(&adapter->ccw_device->dev, "The error threshold for checksum statistics " "has been exceeded\n"); - zfcp_dbf_hba_berr(adapter->dbf, req); + zfcp_dbf_hba_bit_err("fssrh_3", req); break; case FSF_STATUS_READ_LINK_DOWN: zfcp_fsf_status_read_link_down(req); @@ -754,10 +754,11 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio) goto out; failed_req_send: + req->data = NULL; mempool_free(sr_buf, adapter->pool.status_read_data); failed_buf: + zfcp_dbf_hba_fsf_uss("fssr__1", req); zfcp_fsf_req_free(req); - zfcp_dbf_hba_fsf_unsol("fail", adapter->dbf, NULL); out: spin_unlock_irq(&qdio->req_q_lock); return retval; @@ -2420,3 +2421,12 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx) break; } } + +struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *qdio, + struct qdio_buffer *sbal) +{ + struct qdio_buffer_element *sbale = &sbal->element[0]; + u64 req_id = (unsigned long) sbale->addr; + + return zfcp_reqlist_find(qdio->adapter->req_list, req_id); +} diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index a0554beb4179..434a33ba0509 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -74,7 +74,6 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; if (unlikely(qdio_err)) { - zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count); zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err); return; } @@ -97,7 +96,6 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, int sbal_idx, sbal_no; if (unlikely(qdio_err)) { - zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count); zfcp_qdio_handler_error(qdio, "qdires1", qdio_err); return; } -- cgit v1.2.3 From 250a1352b95e1db3216e5c5d4f4365bea5122f4a Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Thu, 2 Dec 2010 15:16:15 +0100 Subject: [SCSI] zfcp: Redesign of the debug tracing for SCSI records. This patch is the continuation to redesign the zfcp tracing to a more straight-forward and easy to extend scheme. This patch deals with all trace records of the zfcp SCSI area. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 232 +++++++++--------------------------------- drivers/s390/scsi/zfcp_dbf.h | 129 ++++++++++++----------- drivers/s390/scsi/zfcp_ext.h | 4 +- drivers/s390/scsi/zfcp_fsf.c | 2 +- drivers/s390/scsi/zfcp_scsi.c | 30 +++--- 5 files changed, 132 insertions(+), 265 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index b57a47b64b80..f9bd094c6e63 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -3,7 +3,7 @@ * * Debug traces for zfcp. * - * Copyright IBM Corporation 2002, 2009 + * Copyright IBM Corporation 2002, 2010 */ #define KMSG_COMPONENT "zfcp" @@ -52,70 +52,6 @@ void zfcp_dbf_pl_write(struct zfcp_dbf *dbf, void *data, u16 length, char *area, spin_unlock(&dbf->pay_lock); } -static void zfcp_dbf_tag(char **p, const char *label, const char *tag) -{ - int i; - - *p += sprintf(*p, "%-24s", label); - for (i = 0; i < ZFCP_DBF_TAG_SIZE; i++) - *p += sprintf(*p, "%c", tag[i]); - *p += sprintf(*p, "\n"); -} - -static void zfcp_dbf_out(char **buf, const char *s, const char *format, ...) -{ - va_list arg; - - *buf += sprintf(*buf, "%-24s", s); - va_start(arg, format); - *buf += vsprintf(*buf, format, arg); - va_end(arg); - *buf += sprintf(*buf, "\n"); -} - -static void zfcp_dbf_outd(char **p, const char *label, char *buffer, - int buflen, int offset, int total_size) -{ - if (!offset) - *p += sprintf(*p, "%-24s ", label); - while (buflen--) { - if (offset > 0) { - if ((offset % 32) == 0) - *p += sprintf(*p, "\n%-24c ", ' '); - else if ((offset % 4) == 0) - *p += sprintf(*p, " "); - } - *p += sprintf(*p, "%02x", *buffer++); - if (++offset == total_size) { - *p += sprintf(*p, "\n"); - break; - } - } - if (!total_size) - *p += sprintf(*p, "\n"); -} - -static int zfcp_dbf_view_header(debug_info_t *id, struct debug_view *view, - int area, debug_entry_t *entry, char *out_buf) -{ - struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)DEBUG_DATA(entry); - struct timespec t; - char *p = out_buf; - - if (strncmp(dump->tag, "dump", ZFCP_DBF_TAG_SIZE) != 0) { - stck_to_timespec(entry->id.stck, &t); - zfcp_dbf_out(&p, "timestamp", "%011lu:%06lu", - t.tv_sec, t.tv_nsec); - zfcp_dbf_out(&p, "cpu", "%02i", entry->id.fields.cpuid); - } else { - zfcp_dbf_outd(&p, "", dump->data, dump->size, dump->offset, - dump->total_size); - if ((dump->offset + dump->size) == dump->total_size) - p += sprintf(p, "\n"); - } - return p - out_buf; -} - /** * zfcp_dbf_hba_fsf_res - trace event for fsf responses * @tag: tag indicating which kind of unsolicited status has been received @@ -393,131 +329,57 @@ void zfcp_dbf_san_in_els(char *tag, struct zfcp_fsf_req *fsf) fsf->req_id, ntoh24(srb->d_id)); } -void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level, - struct zfcp_dbf *dbf, struct scsi_cmnd *scsi_cmnd, - struct zfcp_fsf_req *fsf_req, unsigned long old_req_id) +/** + * zfcp_dbf_scsi - trace event for scsi commands + * @tag: identifier for event + * @sc: pointer to struct scsi_cmnd + * @fsf: pointer to struct zfcp_fsf_req + */ +void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf) { - struct zfcp_dbf_scsi_record *rec = &dbf->scsi_buf; - struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec; - unsigned long flags; + struct zfcp_adapter *adapter = + (struct zfcp_adapter *) sc->device->host->hostdata[0]; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_dbf_scsi *rec = &dbf->scsi_buf; struct fcp_resp_with_ext *fcp_rsp; - struct fcp_resp_rsp_info *fcp_rsp_info = NULL; - char *fcp_sns_info = NULL; - int offset = 0, buflen = 0; + struct fcp_resp_rsp_info *fcp_rsp_info; + unsigned long flags; spin_lock_irqsave(&dbf->scsi_lock, flags); - do { - memset(rec, 0, sizeof(*rec)); - if (offset == 0) { - strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); - strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE); - if (scsi_cmnd != NULL) { - if (scsi_cmnd->device) { - rec->scsi_id = scsi_cmnd->device->id; - rec->scsi_lun = scsi_cmnd->device->lun; - } - rec->scsi_result = scsi_cmnd->result; - rec->scsi_cmnd = (unsigned long)scsi_cmnd; - memcpy(rec->scsi_opcode, scsi_cmnd->cmnd, - min((int)scsi_cmnd->cmd_len, - ZFCP_DBF_SCSI_OPCODE)); - rec->scsi_retries = scsi_cmnd->retries; - rec->scsi_allowed = scsi_cmnd->allowed; - } - if (fsf_req != NULL) { - fcp_rsp = (struct fcp_resp_with_ext *) - &(fsf_req->qtcb->bottom.io.fcp_rsp); - fcp_rsp_info = (struct fcp_resp_rsp_info *) - &fcp_rsp[1]; - fcp_sns_info = (char *) &fcp_rsp[1]; - if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) - fcp_sns_info += fcp_rsp->ext.fr_sns_len; - - rec->rsp_validity = fcp_rsp->resp.fr_flags; - rec->rsp_scsi_status = fcp_rsp->resp.fr_status; - rec->rsp_resid = fcp_rsp->ext.fr_resid; - if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) - rec->rsp_code = fcp_rsp_info->rsp_code; - if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) { - buflen = min(fcp_rsp->ext.fr_sns_len, - (u32)ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO); - rec->sns_info_len = buflen; - memcpy(rec->sns_info, fcp_sns_info, - min(buflen, - ZFCP_DBF_SCSI_FCP_SNS_INFO)); - offset += min(buflen, - ZFCP_DBF_SCSI_FCP_SNS_INFO); - } - - rec->fsf_reqid = fsf_req->req_id; - rec->fsf_seqno = fsf_req->seq_no; - rec->fsf_issued = fsf_req->issued; - } - rec->old_fsf_reqid = old_req_id; - } else { - strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE); - dump->total_size = buflen; - dump->offset = offset; - dump->size = min(buflen - offset, - (int)sizeof(struct - zfcp_dbf_scsi_record) - - (int)sizeof(struct zfcp_dbf_dump)); - memcpy(dump->data, fcp_sns_info + offset, dump->size); - offset += dump->size; - } - debug_event(dbf->scsi, level, rec, sizeof(*rec)); - } while (offset < buflen); - spin_unlock_irqrestore(&dbf->scsi_lock, flags); -} + memset(rec, 0, sizeof(*rec)); -static int zfcp_dbf_scsi_view_format(debug_info_t *id, struct debug_view *view, - char *out_buf, const char *in_buf) -{ - struct zfcp_dbf_scsi_record *r = (struct zfcp_dbf_scsi_record *)in_buf; - struct timespec t; - char *p = out_buf; - - if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) - return 0; - - zfcp_dbf_tag(&p, "tag", r->tag); - zfcp_dbf_tag(&p, "tag2", r->tag2); - zfcp_dbf_out(&p, "scsi_id", "0x%08x", r->scsi_id); - zfcp_dbf_out(&p, "scsi_lun", "0x%08x", r->scsi_lun); - zfcp_dbf_out(&p, "scsi_result", "0x%08x", r->scsi_result); - zfcp_dbf_out(&p, "scsi_cmnd", "0x%0Lx", r->scsi_cmnd); - zfcp_dbf_outd(&p, "scsi_opcode", r->scsi_opcode, ZFCP_DBF_SCSI_OPCODE, - 0, ZFCP_DBF_SCSI_OPCODE); - zfcp_dbf_out(&p, "scsi_retries", "0x%02x", r->scsi_retries); - zfcp_dbf_out(&p, "scsi_allowed", "0x%02x", r->scsi_allowed); - if (strncmp(r->tag, "abrt", ZFCP_DBF_TAG_SIZE) == 0) - zfcp_dbf_out(&p, "old_fsf_reqid", "0x%0Lx", r->old_fsf_reqid); - zfcp_dbf_out(&p, "fsf_reqid", "0x%0Lx", r->fsf_reqid); - zfcp_dbf_out(&p, "fsf_seqno", "0x%08x", r->fsf_seqno); - stck_to_timespec(r->fsf_issued, &t); - zfcp_dbf_out(&p, "fsf_issued", "%011lu:%06lu", t.tv_sec, t.tv_nsec); - - if (strncmp(r->tag, "rslt", ZFCP_DBF_TAG_SIZE) == 0) { - zfcp_dbf_out(&p, "fcp_rsp_validity", "0x%02x", r->rsp_validity); - zfcp_dbf_out(&p, "fcp_rsp_scsi_status", "0x%02x", - r->rsp_scsi_status); - zfcp_dbf_out(&p, "fcp_rsp_resid", "0x%08x", r->rsp_resid); - zfcp_dbf_out(&p, "fcp_rsp_code", "0x%08x", r->rsp_code); - zfcp_dbf_out(&p, "fcp_sns_info_len", "0x%08x", r->sns_info_len); - zfcp_dbf_outd(&p, "fcp_sns_info", r->sns_info, - min((int)r->sns_info_len, - ZFCP_DBF_SCSI_FCP_SNS_INFO), 0, - r->sns_info_len); + memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); + rec->id = ZFCP_DBF_SCSI_CMND; + rec->scsi_result = sc->result; + rec->scsi_retries = sc->retries; + rec->scsi_allowed = sc->allowed; + rec->scsi_id = sc->device->id; + rec->scsi_lun = sc->device->lun; + rec->host_scribble = (unsigned long)sc->host_scribble; + + memcpy(rec->scsi_opcode, sc->cmnd, + min((int)sc->cmd_len, ZFCP_DBF_SCSI_OPCODE)); + + if (fsf) { + rec->fsf_req_id = fsf->req_id; + fcp_rsp = (struct fcp_resp_with_ext *) + &(fsf->qtcb->bottom.io.fcp_rsp); + memcpy(&rec->fcp_rsp, fcp_rsp, FCP_RESP_WITH_EXT); + if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) { + fcp_rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; + rec->fcp_rsp_info = fcp_rsp_info->rsp_code; + } + if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) { + rec->pl_len = min((u16)SCSI_SENSE_BUFFERSIZE, + (u16)ZFCP_DBF_PAY_MAX_REC); + zfcp_dbf_pl_write(dbf, sc->sense_buffer, rec->pl_len, + "fcp_sns", fsf->req_id); + } } - p += sprintf(p, "\n"); - return p - out_buf; -} -static struct debug_view zfcp_dbf_scsi_view = { - .name = "structured", - .header_proc = zfcp_dbf_view_header, - .format_proc = zfcp_dbf_scsi_view_format, -}; + debug_event(adapter->dbf->scsi, 1, rec, sizeof(*rec)); + spin_unlock_irqrestore(&dbf->scsi_lock, flags); +} static debug_info_t *zfcp_dbf_reg(const char *name, int level, struct debug_view *view, int size) @@ -584,8 +446,8 @@ int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter) /* debug feature area which records SCSI command failures and recovery */ sprintf(dbf_name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev)); - dbf->scsi = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_scsi_view, - sizeof(struct zfcp_dbf_scsi_record)); + dbf->scsi = zfcp_dbf_reg(dbf_name, 3, NULL, + sizeof(struct zfcp_dbf_scsi)); if (!dbf->scsi) goto err_out; diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 5dc0b414cf28..2cee8197dd02 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -19,14 +19,6 @@ #define ZFCP_DBF_INVALID_LUN 0xFFFFFFFFFFFFFFFFull -struct zfcp_dbf_dump { - u8 tag[ZFCP_DBF_TAG_SIZE]; - u32 total_size; /* size of total dump data */ - u32 offset; /* how much data has being already dumped */ - u32 size; /* how much data comes with this record */ - u8 data[]; /* dump data */ -} __attribute__ ((packed)); - /** * struct zfcp_dbf_rec_trigger - trace record for triggered recovery action * @ready: number of ready recovery actions @@ -192,6 +184,47 @@ struct zfcp_dbf_hba { } u; } __packed; +/** + * enum zfcp_dbf_scsi_id - scsi trace record identifier + * @ZFCP_DBF_SCSI_CMND: scsi command trace record + */ +enum zfcp_dbf_scsi_id { + ZFCP_DBF_SCSI_CMND = 1, +}; + +/** + * struct zfcp_dbf_scsi - common trace record for SCSI records + * @id: unique number of recovery record type + * @tag: identifier string specifying the location of initiation + * @scsi_id: scsi device id + * @scsi_lun: scsi device logical unit number + * @scsi_result: scsi result + * @scsi_retries: current retry number of scsi request + * @scsi_allowed: allowed retries + * @fcp_rsp_info: FCP response info + * @scsi_opcode: scsi opcode + * @fsf_req_id: request id of fsf request + * @host_scribble: LLD specific data attached to SCSI request + * @pl_len: length of paload stored as zfcp_dbf_pay + * @fsf_rsp: response for fsf request + */ +struct zfcp_dbf_scsi { + u8 id; + char tag[ZFCP_DBF_TAG_LEN]; + u32 scsi_id; + u32 scsi_lun; + u32 scsi_result; + u8 scsi_retries; + u8 scsi_allowed; + u8 fcp_rsp_info; +#define ZFCP_DBF_SCSI_OPCODE 16 + u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE]; + u64 fsf_req_id; + u64 host_scribble; + u16 pl_len; + struct fcp_resp_with_ext fcp_rsp; +} __packed; + /** * struct zfcp_dbf_pay - trace record for unformatted payload information * @area: area this record is originated from @@ -207,31 +240,6 @@ struct zfcp_dbf_pay { char data[ZFCP_DBF_PAY_MAX_REC]; } __packed; -struct zfcp_dbf_scsi_record { - u8 tag[ZFCP_DBF_TAG_SIZE]; - u8 tag2[ZFCP_DBF_TAG_SIZE]; - u32 scsi_id; - u32 scsi_lun; - u32 scsi_result; - u64 scsi_cmnd; -#define ZFCP_DBF_SCSI_OPCODE 16 - u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE]; - u8 scsi_retries; - u8 scsi_allowed; - u64 fsf_reqid; - u32 fsf_seqno; - u64 fsf_issued; - u64 old_fsf_reqid; - u8 rsp_validity; - u8 rsp_scsi_status; - u32 rsp_resid; - u8 rsp_code; -#define ZFCP_DBF_SCSI_FCP_SNS_INFO 16 -#define ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO 256 - u32 sns_info_len; - u8 sns_info[ZFCP_DBF_SCSI_FCP_SNS_INFO]; -} __attribute__ ((packed)); - struct zfcp_dbf { debug_info_t *pay; debug_info_t *rec; @@ -246,7 +254,7 @@ struct zfcp_dbf { struct zfcp_dbf_rec rec_buf; struct zfcp_dbf_hba hba_buf; struct zfcp_dbf_san san_buf; - struct zfcp_dbf_scsi_record scsi_buf; + struct zfcp_dbf_scsi scsi_buf; struct zfcp_dbf_pay pay_buf; struct zfcp_adapter *adapter; }; @@ -260,7 +268,7 @@ void zfcp_dbf_hba_fsf_resp(char *tag, int level, struct zfcp_fsf_req *req) /** * zfcp_dbf_hba_fsf_response - trace event for request completion - * @fsf_req: request that has been completed + * @req: request that has been completed */ static inline void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req) @@ -287,57 +295,53 @@ void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req) } static inline -void zfcp_dbf_scsi(const char *tag, const char *tag2, int level, - struct zfcp_dbf *dbf, struct scsi_cmnd *scmd, - struct zfcp_fsf_req *req, unsigned long old_id) +void _zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *scmd, + struct zfcp_fsf_req *req) { - if (level <= dbf->scsi->level) - _zfcp_dbf_scsi(tag, tag2, level, dbf, scmd, req, old_id); + struct zfcp_adapter *adapter = (struct zfcp_adapter *) + scmd->device->host->hostdata[0]; + + if (level <= adapter->dbf->scsi->level) + zfcp_dbf_scsi(tag, scmd, req); } /** * zfcp_dbf_scsi_result - trace event for SCSI command completion - * @dbf: adapter dbf trace * @scmd: SCSI command pointer * @req: FSF request used to issue SCSI command */ static inline -void zfcp_dbf_scsi_result(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd, - struct zfcp_fsf_req *req) +void zfcp_dbf_scsi_result(struct scsi_cmnd *scmd, struct zfcp_fsf_req *req) { if (scmd->result != 0) - zfcp_dbf_scsi("rslt", "erro", 3, dbf, scmd, req, 0); + _zfcp_dbf_scsi("rsl_err", 3, scmd, req); else if (scmd->retries > 0) - zfcp_dbf_scsi("rslt", "retr", 4, dbf, scmd, req, 0); + _zfcp_dbf_scsi("rsl_ret", 4, scmd, req); else - zfcp_dbf_scsi("rslt", "norm", 6, dbf, scmd, req, 0); + _zfcp_dbf_scsi("rsl_nor", 6, scmd, req); } /** * zfcp_dbf_scsi_fail_send - trace event for failure to send SCSI command - * @dbf: adapter dbf trace * @scmd: SCSI command pointer */ static inline -void zfcp_dbf_scsi_fail_send(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd) +void zfcp_dbf_scsi_fail_send(struct scsi_cmnd *scmd) { - zfcp_dbf_scsi("rslt", "fail", 4, dbf, scmd, NULL, 0); + _zfcp_dbf_scsi("rsl_fai", 4, scmd, NULL); } /** * zfcp_dbf_scsi_abort - trace event for SCSI command abort * @tag: tag indicating success or failure of abort operation - * @adapter: adapter thas has been used to issue SCSI command to be aborted * @scmd: SCSI command to be aborted - * @new_req: request containing abort (might be NULL) - * @old_id: identifier of request containg SCSI command to be aborted + * @fsf_req: request containing abort (might be NULL) */ static inline -void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf, - struct scsi_cmnd *scmd, struct zfcp_fsf_req *new_req, - unsigned long old_id) +void zfcp_dbf_scsi_abort(char *tag, struct scsi_cmnd *scmd, + struct zfcp_fsf_req *fsf_req) { - zfcp_dbf_scsi("abrt", tag, 1, dbf, scmd, new_req, old_id); + _zfcp_dbf_scsi(tag, 1, scmd, fsf_req); } /** @@ -347,12 +351,17 @@ void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf, * @flag: indicates type of reset (Target Reset, Logical Unit Reset) */ static inline -void zfcp_dbf_scsi_devreset(const char *tag, struct scsi_cmnd *scmnd, u8 flag) +void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag) { - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device); + char tmp_tag[ZFCP_DBF_TAG_LEN]; + + if (flag == FCP_TMF_TGT_RESET) + memcpy(tmp_tag, "tr_", 3); + else + memcpy(tmp_tag, "lr_", 3); - zfcp_dbf_scsi(flag == FCP_TMF_TGT_RESET ? "trst" : "lrst", tag, 1, - zfcp_sdev->port->adapter->dbf, scmnd, NULL, 0); + memcpy(&tmp_tag[3], tag, 4); + _zfcp_dbf_scsi(tmp_tag, 1, scmnd, NULL); } #endif /* ZFCP_DBF_H */ diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 00875de2cb99..b68a546275a5 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -56,9 +56,7 @@ extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *); extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32); extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *); -extern void _zfcp_dbf_scsi(const char *, const char *, int, struct zfcp_dbf *, - struct scsi_cmnd *, struct zfcp_fsf_req *, - unsigned long); +extern void zfcp_dbf_scsi(char *, struct scsi_cmnd *, struct zfcp_fsf_req *); /* zfcp_erp.c */ extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 9881ba947f11..5bb118e01f36 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -2105,7 +2105,7 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req) skip_fsfstatus: zfcp_fsf_req_trace(req, scpnt); - zfcp_dbf_scsi_result(req->adapter->dbf, scpnt, req); + zfcp_dbf_scsi_result(scpnt, req); scpnt->host_scribble = NULL; (scpnt->scsi_done) (scpnt); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 63529ed801eb..8c5c1c89c098 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -68,11 +68,8 @@ static int zfcp_scsi_slave_configure(struct scsi_device *sdp) static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) { - struct zfcp_adapter *adapter = - (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; - set_host_byte(scpnt, result); - zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt); + zfcp_dbf_scsi_fail_send(scpnt); scpnt->scsi_done(scpnt); } @@ -80,7 +77,6 @@ static int zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); - struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device)); int status, scsi_result, ret; @@ -91,7 +87,7 @@ int zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt) scsi_result = fc_remote_port_chkready(rport); if (unlikely(scsi_result)) { scpnt->result = scsi_result; - zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt); + zfcp_dbf_scsi_fail_send(scpnt); scpnt->scsi_done(scpnt); return 0; } @@ -182,8 +178,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) old_req = zfcp_reqlist_find(adapter->req_list, old_reqid); if (!old_req) { write_unlock_irqrestore(&adapter->abort_lock, flags); - zfcp_dbf_scsi_abort("lte1", adapter->dbf, scpnt, NULL, - old_reqid); + zfcp_dbf_scsi_abort("abrt_or", scpnt, NULL); return FAILED; /* completion could be in progress */ } old_req->data = NULL; @@ -198,29 +193,32 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) zfcp_erp_wait(adapter); ret = fc_block_scsi_eh(scpnt); - if (ret) + if (ret) { + zfcp_dbf_scsi_abort("abrt_bl", scpnt, NULL); return ret; + } if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) { - zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL, - old_reqid); + zfcp_dbf_scsi_abort("abrt_ru", scpnt, NULL); return SUCCESS; } } - if (!abrt_req) + if (!abrt_req) { + zfcp_dbf_scsi_abort("abrt_ar", scpnt, NULL); return FAILED; + } wait_for_completion(&abrt_req->completion); if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) - dbf_tag = "okay"; + dbf_tag = "abrt_ok"; else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) - dbf_tag = "lte2"; + dbf_tag = "abrt_nn"; else { - dbf_tag = "fail"; + dbf_tag = "abrt_fa"; retval = FAILED; } - zfcp_dbf_scsi_abort(dbf_tag, adapter->dbf, scpnt, abrt_req, old_reqid); + zfcp_dbf_scsi_abort(dbf_tag, scpnt, abrt_req); zfcp_fsf_req_free(abrt_req); return retval; } -- cgit v1.2.3 From ea4a3a6ac40e2a585654808d4aefb39a6d57dca0 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Thu, 2 Dec 2010 15:16:16 +0100 Subject: [SCSI] zfcp: Redesign of the debug tracing final cleanup. This patch is the final cleanup of the redesign from the zfcp tracing. Structures and elements which were used by multiple areas of the former debug tracing are now changed to the new scheme. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 5 +-- drivers/s390/scsi/zfcp_ccw.c | 14 +++--- drivers/s390/scsi/zfcp_cfdc.c | 8 ++-- drivers/s390/scsi/zfcp_dbf.c | 70 +++++++++++++++--------------- drivers/s390/scsi/zfcp_dbf.h | 25 ++++++++--- drivers/s390/scsi/zfcp_erp.c | 97 ++++++++++++++++++++---------------------- drivers/s390/scsi/zfcp_ext.h | 18 ++++---- drivers/s390/scsi/zfcp_fc.c | 18 ++++---- drivers/s390/scsi/zfcp_fsf.c | 85 +++++++++++++++++------------------- drivers/s390/scsi/zfcp_qdio.c | 6 +-- drivers/s390/scsi/zfcp_scsi.c | 6 +-- drivers/s390/scsi/zfcp_sysfs.c | 9 ++-- 12 files changed, 180 insertions(+), 181 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 044fb22718d2..352ca0d4ca25 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -311,8 +311,7 @@ int zfcp_status_read_refill(struct zfcp_adapter *adapter) if (zfcp_fsf_status_read(adapter->qdio)) { if (atomic_read(&adapter->stat_miss) >= adapter->stat_read_buf_num) { - zfcp_erp_adapter_reopen(adapter, 0, "axsref1", - NULL); + zfcp_erp_adapter_reopen(adapter, 0, "axsref1"); return 1; } break; @@ -459,7 +458,7 @@ void zfcp_adapter_unregister(struct zfcp_adapter *adapter) sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs); zfcp_erp_thread_kill(adapter); - zfcp_dbf_adapter_unregister(adapter->dbf); + zfcp_dbf_adapter_unregister(adapter); zfcp_qdio_destroy(adapter->qdio); zfcp_ccw_adapter_put(adapter); /* final put to release */ diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 0833c2b51e39..4f7852dd30c7 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -48,7 +48,7 @@ static int zfcp_ccw_activate(struct ccw_device *cdev) zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, - "ccresu2", NULL); + "ccresu2"); zfcp_erp_wait(adapter); flush_work(&adapter->scan_work); @@ -182,7 +182,7 @@ static int zfcp_ccw_set_offline(struct ccw_device *cdev) if (!adapter) return 0; - zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); + zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1"); zfcp_erp_wait(adapter); zfcp_ccw_adapter_put(adapter); @@ -207,24 +207,24 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event) switch (event) { case CIO_GONE: dev_warn(&cdev->dev, "The FCP device has been detached\n"); - zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL); + zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1"); break; case CIO_NO_PATH: dev_warn(&cdev->dev, "The CHPID for the FCP device is offline\n"); - zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL); + zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2"); break; case CIO_OPER: dev_info(&cdev->dev, "The FCP device is operational again\n"); zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, - "ccnoti4", NULL); + "ccnoti4"); break; case CIO_BOXED: dev_warn(&cdev->dev, "The FCP device did not respond within " "the specified time\n"); - zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL); + zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5"); break; } @@ -243,7 +243,7 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) if (!adapter) return; - zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); + zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1"); zfcp_erp_wait(adapter); zfcp_erp_thread_kill(adapter); diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index d692e229ecba..46342fee394d 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -288,7 +288,7 @@ void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *adapter) (status & ZFCP_STATUS_COMMON_ACCESS_BOXED)) zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, - "cfaac_1", NULL); + "cfaac_1"); } read_unlock_irqrestore(&adapter->port_list_lock, flags); @@ -299,7 +299,7 @@ void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *adapter) (status & ZFCP_STATUS_COMMON_ACCESS_BOXED)) zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, - "cfaac_2", NULL); + "cfaac_2"); } } @@ -426,7 +426,7 @@ int zfcp_cfdc_open_lun_eval(struct scsi_device *sdev, zfcp_scsi_dev_lun(sdev), (unsigned long long)zfcp_sdev->port->wwpn); zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); - zfcp_erp_lun_shutdown(sdev, 0, "fsouh_6", NULL); + zfcp_erp_lun_shutdown(sdev, 0, "fsouh_6"); return -EACCES; } @@ -437,7 +437,7 @@ int zfcp_cfdc_open_lun_eval(struct scsi_device *sdev, zfcp_scsi_dev_lun(sdev), (unsigned long long)zfcp_sdev->port->wwpn); zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); - zfcp_erp_lun_shutdown(sdev, 0, "fsosh_8", NULL); + zfcp_erp_lun_shutdown(sdev, 0, "fsosh_8"); return -EACCES; } diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index f9bd094c6e63..96d1462e0bf5 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -377,26 +377,37 @@ void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf) } } - debug_event(adapter->dbf->scsi, 1, rec, sizeof(*rec)); + debug_event(dbf->scsi, 1, rec, sizeof(*rec)); spin_unlock_irqrestore(&dbf->scsi_lock, flags); } -static debug_info_t *zfcp_dbf_reg(const char *name, int level, - struct debug_view *view, int size) +static debug_info_t *zfcp_dbf_reg(const char *name, int size, int rec_size) { struct debug_info *d; - d = debug_register(name, dbfsize, level, size); + d = debug_register(name, size, 1, rec_size); if (!d) return NULL; debug_register_view(d, &debug_hex_ascii_view); - debug_register_view(d, view); - debug_set_level(d, level); + debug_set_level(d, 3); return d; } +static void zfcp_dbf_unregister(struct zfcp_dbf *dbf) +{ + if (!dbf) + return; + + debug_unregister(dbf->scsi); + debug_unregister(dbf->san); + debug_unregister(dbf->hba); + debug_unregister(dbf->pay); + debug_unregister(dbf->rec); + kfree(dbf); +} + /** * zfcp_adapter_debug_register - registers debug feature for an adapter * @adapter: pointer to adapter for which debug features should be registered @@ -404,15 +415,13 @@ static debug_info_t *zfcp_dbf_reg(const char *name, int level, */ int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter) { - char dbf_name[DEBUG_MAX_NAME_LEN]; + char name[DEBUG_MAX_NAME_LEN]; struct zfcp_dbf *dbf; dbf = kzalloc(sizeof(struct zfcp_dbf), GFP_KERNEL); if (!dbf) return -ENOMEM; - dbf->adapter = adapter; - spin_lock_init(&dbf->pay_lock); spin_lock_init(&dbf->hba_lock); spin_lock_init(&dbf->san_lock); @@ -420,59 +429,52 @@ int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter) spin_lock_init(&dbf->rec_lock); /* debug feature area which records recovery activity */ - sprintf(dbf_name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev)); - dbf->rec = zfcp_dbf_reg(dbf_name, 3, NULL, sizeof(struct zfcp_dbf_rec)); + sprintf(name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev)); + dbf->rec = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_rec)); if (!dbf->rec) goto err_out; /* debug feature area which records HBA (FSF and QDIO) conditions */ - sprintf(dbf_name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev)); - dbf->hba = zfcp_dbf_reg(dbf_name, 3, NULL, sizeof(struct zfcp_dbf_hba)); + sprintf(name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev)); + dbf->hba = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_hba)); if (!dbf->hba) goto err_out; /* debug feature area which records payload info */ - sprintf(dbf_name, "zfcp_%s_pay", dev_name(&adapter->ccw_device->dev)); - dbf->pay = zfcp_dbf_reg(dbf_name, 3, NULL, - sizeof(struct zfcp_dbf_pay)); + sprintf(name, "zfcp_%s_pay", dev_name(&adapter->ccw_device->dev)); + dbf->pay = zfcp_dbf_reg(name, dbfsize * 2, sizeof(struct zfcp_dbf_pay)); if (!dbf->pay) goto err_out; /* debug feature area which records SAN command failures and recovery */ - sprintf(dbf_name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev)); - dbf->san = zfcp_dbf_reg(dbf_name, 3, NULL, sizeof(struct zfcp_dbf_san)); + sprintf(name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev)); + dbf->san = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_san)); if (!dbf->san) goto err_out; /* debug feature area which records SCSI command failures and recovery */ - sprintf(dbf_name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev)); - dbf->scsi = zfcp_dbf_reg(dbf_name, 3, NULL, - sizeof(struct zfcp_dbf_scsi)); + sprintf(name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev)); + dbf->scsi = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_scsi)); if (!dbf->scsi) goto err_out; adapter->dbf = dbf; - return 0; + return 0; err_out: - zfcp_dbf_adapter_unregister(dbf); + zfcp_dbf_unregister(dbf); return -ENOMEM; } /** * zfcp_adapter_debug_unregister - unregisters debug feature for an adapter - * @dbf: pointer to dbf for which debug features should be unregistered + * @adapter: pointer to adapter for which debug features should be unregistered */ -void zfcp_dbf_adapter_unregister(struct zfcp_dbf *dbf) +void zfcp_dbf_adapter_unregister(struct zfcp_adapter *adapter) { - if (!dbf) - return; - debug_unregister(dbf->scsi); - debug_unregister(dbf->san); - debug_unregister(dbf->hba); - debug_unregister(dbf->pay); - debug_unregister(dbf->rec); - dbf->adapter->dbf = NULL; - kfree(dbf); + struct zfcp_dbf *dbf = adapter->dbf; + + adapter->dbf = NULL; + zfcp_dbf_unregister(dbf); } diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 2cee8197dd02..714f087eb7a9 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -14,8 +14,6 @@ #include "zfcp_def.h" #define ZFCP_DBF_TAG_LEN 7 -#define ZFCP_DBF_TAG_SIZE 4 -#define ZFCP_DBF_ID_SIZE 7 #define ZFCP_DBF_INVALID_LUN 0xFFFFFFFFFFFFFFFFull @@ -233,13 +231,31 @@ struct zfcp_dbf_scsi { * @data: unformatted data */ struct zfcp_dbf_pay { + u8 counter; char area[ZFCP_DBF_TAG_LEN]; - char counter; u64 fsf_req_id; #define ZFCP_DBF_PAY_MAX_REC 0x100 char data[ZFCP_DBF_PAY_MAX_REC]; } __packed; +/** + * struct zfcp_dbf - main dbf trace structure + * @pay: reference to payload trace area + * @rec: reference to recovery trace area + * @hba: reference to hba trace area + * @san: reference to san trace area + * @scsi: reference to scsi trace area + * @pay_lock: lock protecting payload trace buffer + * @rec_lock: lock protecting recovery trace buffer + * @hba_lock: lock protecting hba trace buffer + * @san_lock: lock protecting san trace buffer + * @scsi_lock: lock protecting scsi trace buffer + * @pay_buf: pre-allocated buffer for payload + * @rec_buf: pre-allocated buffer for recovery + * @hba_buf: pre-allocated buffer for hba + * @san_buf: pre-allocated buffer for san + * @scsi_buf: pre-allocated buffer for scsi + */ struct zfcp_dbf { debug_info_t *pay; debug_info_t *rec; @@ -251,12 +267,11 @@ struct zfcp_dbf { spinlock_t hba_lock; spinlock_t san_lock; spinlock_t scsi_lock; + struct zfcp_dbf_pay pay_buf; struct zfcp_dbf_rec rec_buf; struct zfcp_dbf_hba hba_buf; struct zfcp_dbf_san san_buf; struct zfcp_dbf_scsi scsi_buf; - struct zfcp_dbf_pay pay_buf; - struct zfcp_adapter *adapter; }; static inline diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 62b1b4a03ee3..066f9ea67502 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -236,7 +236,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, struct zfcp_port *port, struct scsi_device *sdev, - char *id, void *ref, u32 act_status) + char *id, u32 act_status) { int retval = 1, need; struct zfcp_erp_action *act; @@ -262,7 +262,7 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, } static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, - int clear_mask, char *id, void *ref) + int clear_mask, char *id) { zfcp_erp_adapter_block(adapter, clear_mask); zfcp_scsi_schedule_rports_block(adapter); @@ -274,7 +274,7 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, return -EIO; } return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, - adapter, NULL, NULL, id, ref, 0); + adapter, NULL, NULL, id, 0); } /** @@ -282,10 +282,8 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, * @adapter: Adapter to reopen. * @clear: Status flags to clear. * @id: Id for debug trace event. - * @ref: Reference for debug trace event. */ -void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, - char *id, void *ref) +void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, char *id) { unsigned long flags; @@ -298,7 +296,7 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, ZFCP_STATUS_COMMON_ERP_FAILED); else zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, - NULL, NULL, id, ref, 0); + NULL, NULL, id, 0); write_unlock_irqrestore(&adapter->erp_lock, flags); } @@ -307,13 +305,12 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, * @adapter: Adapter to shut down. * @clear: Status flags to clear. * @id: Id for debug trace event. - * @ref: Reference for debug trace event. */ void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, - char *id, void *ref) + char *id) { int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; - zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref); + zfcp_erp_adapter_reopen(adapter, clear | flags, id); } /** @@ -321,13 +318,11 @@ void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, * @port: Port to shut down. * @clear: Status flags to clear. * @id: Id for debug trace event. - * @ref: Reference for debug trace event. */ -void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id, - void *ref) +void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id) { int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; - zfcp_erp_port_reopen(port, clear | flags, id, ref); + zfcp_erp_port_reopen(port, clear | flags, id); } static void zfcp_erp_port_block(struct zfcp_port *port, int clear) @@ -336,8 +331,8 @@ static void zfcp_erp_port_block(struct zfcp_port *port, int clear) ZFCP_STATUS_COMMON_UNBLOCKED | clear); } -static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, - int clear, char *id, void *ref) +static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, + char *id) { zfcp_erp_port_block(port, clear); zfcp_scsi_schedule_rport_block(port); @@ -346,28 +341,26 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, return; zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, - port->adapter, port, NULL, id, ref, 0); + port->adapter, port, NULL, id, 0); } /** * zfcp_erp_port_forced_reopen - Forced close of port and open again * @port: Port to force close and to reopen. + * @clear: Status flags to clear. * @id: Id for debug trace event. - * @ref: Reference for debug trace event. */ -void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id, - void *ref) +void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id) { unsigned long flags; struct zfcp_adapter *adapter = port->adapter; write_lock_irqsave(&adapter->erp_lock, flags); - _zfcp_erp_port_forced_reopen(port, clear, id, ref); + _zfcp_erp_port_forced_reopen(port, clear, id); write_unlock_irqrestore(&adapter->erp_lock, flags); } -static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, - void *ref) +static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id) { zfcp_erp_port_block(port, clear); zfcp_scsi_schedule_rport_block(port); @@ -379,24 +372,25 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, } return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, - port->adapter, port, NULL, id, ref, 0); + port->adapter, port, NULL, id, 0); } /** * zfcp_erp_port_reopen - trigger remote port recovery * @port: port to recover * @clear_mask: flags in port status to be cleared + * @id: Id for debug trace event. * * Returns 0 if recovery has been triggered, < 0 if not. */ -int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref) +int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id) { int retval; unsigned long flags; struct zfcp_adapter *adapter = port->adapter; write_lock_irqsave(&adapter->erp_lock, flags); - retval = _zfcp_erp_port_reopen(port, clear, id, ref); + retval = _zfcp_erp_port_reopen(port, clear, id); write_unlock_irqrestore(&adapter->erp_lock, flags); return retval; @@ -409,7 +403,7 @@ static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask) } static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, - void *ref, u32 act_status) + u32 act_status) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; @@ -420,17 +414,18 @@ static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, return; zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter, - zfcp_sdev->port, sdev, id, ref, act_status); + zfcp_sdev->port, sdev, id, act_status); } /** * zfcp_erp_lun_reopen - initiate reopen of a LUN * @sdev: SCSI device / LUN to be reopened * @clear_mask: specifies flags in LUN status to be cleared + * @id: Id for debug trace event. + * * Return: 0 on success, < 0 on error */ -void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, - void *ref) +void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id) { unsigned long flags; struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); @@ -438,7 +433,7 @@ void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, struct zfcp_adapter *adapter = port->adapter; write_lock_irqsave(&adapter->erp_lock, flags); - _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0); + _zfcp_erp_lun_reopen(sdev, clear, id, 0); write_unlock_irqrestore(&adapter->erp_lock, flags); } @@ -447,13 +442,11 @@ void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, * @sdev: SCSI device / LUN to shut down. * @clear: Status flags to clear. * @id: Id for debug trace event. - * @ref: Reference for debug trace event. */ -void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id, - void *ref) +void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id) { int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; - zfcp_erp_lun_reopen(sdev, clear | flags, id, ref); + zfcp_erp_lun_reopen(sdev, clear | flags, id); } /** @@ -475,7 +468,7 @@ void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id) int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; write_lock_irqsave(&adapter->erp_lock, flags); - _zfcp_erp_lun_reopen(sdev, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF); + _zfcp_erp_lun_reopen(sdev, clear, id, ZFCP_STATUS_ERP_NO_REF); write_unlock_irqrestore(&adapter->erp_lock, flags); zfcp_erp_wait(adapter); @@ -584,40 +577,40 @@ static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) } static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, - int clear, char *id, void *ref) + int clear, char *id) { struct zfcp_port *port; read_lock(&adapter->port_list_lock); list_for_each_entry(port, &adapter->port_list, list) - _zfcp_erp_port_reopen(port, clear, id, ref); + _zfcp_erp_port_reopen(port, clear, id); read_unlock(&adapter->port_list_lock); } static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear, - char *id, void *ref) + char *id) { struct scsi_device *sdev; shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) - _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0); + _zfcp_erp_lun_reopen(sdev, clear, id, 0); } static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) { switch (act->action) { case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL); + _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1"); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL); + _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2"); break; case ZFCP_ERP_ACTION_REOPEN_PORT: - _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL); + _zfcp_erp_port_reopen(act->port, 0, "ersff_3"); break; case ZFCP_ERP_ACTION_REOPEN_LUN: - _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", NULL, 0); + _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", 0); break; } } @@ -626,13 +619,13 @@ static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act) { switch (act->action) { case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL); + _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1"); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL); + _zfcp_erp_port_reopen(act->port, 0, "ersfs_2"); break; case ZFCP_ERP_ACTION_REOPEN_PORT: - _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3", NULL); + _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3"); break; } } @@ -669,7 +662,7 @@ static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) adapter->peer_d_id); if (IS_ERR(port)) /* error or port already attached */ return; - _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL); + _zfcp_erp_port_reopen(port, 0, "ereptp1"); } static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) @@ -1163,7 +1156,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { _zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, - "ersscg1", NULL); + "ersscg1"); return ZFCP_ERP_EXIT; } break; @@ -1173,7 +1166,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) if (zfcp_erp_strat_change_det(&port->status, erp_status)) { _zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, - "ersscg2", NULL); + "ersscg2"); return ZFCP_ERP_EXIT; } break; @@ -1183,7 +1176,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) { _zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, - "ersscg3", NULL, 0); + "ersscg3", 0); return ZFCP_ERP_EXIT; } break; @@ -1310,7 +1303,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; } if (adapter->erp_total_count == adapter->erp_low_mem_count) - _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL); + _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1"); else { zfcp_erp_strategy_memwait(erp_action); retval = ZFCP_ERP_CONTINUES; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index b68a546275a5..6e325284fbe7 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -45,7 +45,7 @@ extern void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *); /* zfcp_dbf.c */ extern int zfcp_dbf_adapter_register(struct zfcp_adapter *); -extern void zfcp_dbf_adapter_unregister(struct zfcp_dbf *); +extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *); extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *, struct zfcp_port *, struct scsi_device *, u8, u8); extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *); @@ -61,19 +61,17 @@ extern void zfcp_dbf_scsi(char *, struct scsi_cmnd *, struct zfcp_fsf_req *); /* zfcp_erp.c */ extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32); extern void zfcp_erp_clear_adapter_status(struct zfcp_adapter *, u32); -extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *, void *); -extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *, - void *); +extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *); +extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *); extern void zfcp_erp_set_port_status(struct zfcp_port *, u32); extern void zfcp_erp_clear_port_status(struct zfcp_port *, u32); -extern int zfcp_erp_port_reopen(struct zfcp_port *, int, char *, void *); -extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *, void *); -extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *, - void *); +extern int zfcp_erp_port_reopen(struct zfcp_port *, int, char *); +extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *); +extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *); extern void zfcp_erp_set_lun_status(struct scsi_device *, u32); extern void zfcp_erp_clear_lun_status(struct scsi_device *, u32); -extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *, void *); -extern void zfcp_erp_lun_shutdown(struct scsi_device *, int, char *, void *); +extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *); +extern void zfcp_erp_lun_shutdown(struct scsi_device *, int, char *); extern void zfcp_erp_lun_shutdown_wait(struct scsi_device *, char *); extern int zfcp_erp_thread_setup(struct zfcp_adapter *); extern void zfcp_erp_thread_kill(struct zfcp_adapter *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 7d44d9c59bdc..30cf91a787a3 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -174,7 +174,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, if (!port->d_id) zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, - "fcrscn1", NULL); + "fcrscn1"); } read_unlock_irqrestore(&adapter->port_list_lock, flags); } @@ -215,7 +215,7 @@ static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn) read_lock_irqsave(&adapter->port_list_lock, flags); list_for_each_entry(port, &adapter->port_list, list) if (port->wwpn == wwpn) { - zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req); + zfcp_erp_port_forced_reopen(port, 0, "fciwwp1"); break; } read_unlock_irqrestore(&adapter->port_list_lock, flags); @@ -360,7 +360,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work) ret = zfcp_fc_ns_gid_pn(port); if (ret) { /* could not issue gid_pn for some reason */ - zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1", NULL); + zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1"); goto out; } @@ -369,7 +369,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work) goto out; } - zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL); + zfcp_erp_port_reopen(port, 0, "fcgpn_3"); out: put_device(&port->dev); } @@ -426,7 +426,7 @@ static void zfcp_fc_adisc_handler(void *data) if (adisc->els.status) { /* request rejected or timed out */ zfcp_erp_port_forced_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, - "fcadh_1", NULL); + "fcadh_1"); goto out; } @@ -436,7 +436,7 @@ static void zfcp_fc_adisc_handler(void *data) if ((port->wwpn != adisc_resp->adisc_wwpn) || !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) { zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, - "fcadh_2", NULL); + "fcadh_2"); goto out; } @@ -507,7 +507,7 @@ void zfcp_fc_link_test_work(struct work_struct *work) /* send of ADISC was not possible */ atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); - zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL); + zfcp_erp_port_forced_reopen(port, 0, "fcltwk1"); out: put_device(&port->dev); @@ -659,7 +659,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft, port = zfcp_port_enqueue(adapter, acc->fp_wwpn, ZFCP_STATUS_COMMON_NOESC, d_id); if (!IS_ERR(port)) - zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL); + zfcp_erp_port_reopen(port, 0, "fcegpf1"); else if (PTR_ERR(port) != -EEXIST) ret = PTR_ERR(port); } @@ -671,7 +671,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft, write_unlock_irqrestore(&adapter->port_list_lock, flags); list_for_each_entry_safe(port, tmp, &remove_lh, list) { - zfcp_erp_port_shutdown(port, 0, "fcegpf2", NULL); + zfcp_erp_port_shutdown(port, 0, "fcegpf2"); zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs); } diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 5bb118e01f36..60ff9d172c79 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -23,7 +23,7 @@ static void zfcp_fsf_request_timeout_handler(unsigned long data) struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; zfcp_qdio_siosl(adapter); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, - "fsrth_1", NULL); + "fsrth_1"); } static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, @@ -65,7 +65,7 @@ static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req) { dev_err(&req->adapter->ccw_device->dev, "FCP device not " "operational because of an unsupported FC class\n"); - zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1", req); + zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; } @@ -98,7 +98,7 @@ static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) read_lock_irqsave(&adapter->port_list_lock, flags); list_for_each_entry(port, &adapter->port_list, list) if (port->d_id == d_id) { - zfcp_erp_port_reopen(port, 0, "fssrpc1", req); + zfcp_erp_port_reopen(port, 0, "fssrpc1"); break; } read_unlock_irqrestore(&adapter->port_list_lock, flags); @@ -247,7 +247,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, - "fssrh_2", req); + "fssrh_2"); zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0); break; @@ -287,7 +287,7 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req) "The FCP adapter reported a problem " "that cannot be recovered\n"); zfcp_qdio_siosl(req->adapter); - zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req); + zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1"); break; } /* all non-return stats set FSFREQ_ERROR*/ @@ -304,7 +304,7 @@ static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req) dev_err(&req->adapter->ccw_device->dev, "The FCP adapter does not recognize the command 0x%x\n", req->qtcb->header.fsf_command); - zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1", req); + zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -335,17 +335,17 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) "QTCB version 0x%x not supported by FCP adapter " "(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION, psq->word[0], psq->word[1]); - zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1"); break; case FSF_PROT_ERROR_STATE: case FSF_PROT_SEQ_NUMB_ERROR: - zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req); + zfcp_erp_adapter_reopen(adapter, 0, "fspse_2"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PROT_UNSUPP_QTCB_TYPE: dev_err(&adapter->ccw_device->dev, "The QTCB type is not supported by the FCP adapter\n"); - zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3"); break; case FSF_PROT_HOST_CONNECTION_INITIALIZING: atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, @@ -355,12 +355,12 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) dev_err(&adapter->ccw_device->dev, "0x%Lx is an ambiguous request identifier\n", (unsigned long long)qtcb->bottom.support.req_handle); - zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4"); break; case FSF_PROT_LINK_DOWN: zfcp_fsf_link_down_info_eval(req, &psq->link_down_info); /* go through reopen to flush pending requests */ - zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req); + zfcp_erp_adapter_reopen(adapter, 0, "fspse_6"); break; case FSF_PROT_REEST_QUEUE: /* All ports should be marked as ready to run again */ @@ -369,14 +369,14 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, - "fspse_8", req); + "fspse_8"); break; default: dev_err(&adapter->ccw_device->dev, "0x%x is not a valid transfer protocol status\n", qtcb->prefix.prot_status); zfcp_qdio_siosl(adapter); - zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9"); } req->status |= ZFCP_STATUS_FSFREQ_ERROR; } @@ -482,7 +482,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) dev_err(&adapter->ccw_device->dev, "Unknown or unsupported arbitrated loop " "fibre channel topology detected\n"); - zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1"); return -EIO; } @@ -518,7 +518,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) "FCP adapter maximum QTCB size (%d bytes) " "is too small\n", bottom->max_qtcb_size); - zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1"); return; } atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, @@ -536,7 +536,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) &qtcb->header.fsf_status_qual.link_down_info); break; default: - zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3"); return; } @@ -552,14 +552,14 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) dev_err(&adapter->ccw_device->dev, "The FCP adapter only supports newer " "control block versions\n"); - zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4"); return; } if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) { dev_err(&adapter->ccw_device->dev, "The FCP adapter only supports older " "control block versions\n"); - zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5"); } } @@ -700,7 +700,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) del_timer(&req->timer); /* lookup request again, list might have changed */ zfcp_reqlist_find_rm(adapter->req_list, req_id); - zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1", req); + zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1"); return -EIO; } @@ -777,14 +777,13 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) case FSF_PORT_HANDLE_NOT_VALID: if (fsq->word[0] == fsq->word[1]) { zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, - "fsafch1", req); + "fsafch1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; } break; case FSF_LUN_HANDLE_NOT_VALID: if (fsq->word[0] == fsq->word[1]) { - zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2", - req); + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; } break; @@ -795,14 +794,13 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) zfcp_erp_set_port_status(zfcp_sdev->port, ZFCP_STATUS_COMMON_ACCESS_BOXED); zfcp_erp_port_reopen(zfcp_sdev->port, - ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3", - req); + ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_BOXED: zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED); zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, - "fsafch4", req); + "fsafch4"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -903,7 +901,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req); + zfcp_erp_adapter_reopen(adapter, 0, "fsscth1"); /* fall through */ case FSF_GENERIC_COMMAND_REJECTED: case FSF_PAYLOAD_SIZE_MISMATCH: @@ -1449,7 +1447,7 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req) switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1", req); + zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1581,7 +1579,7 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req) if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) { req->status |= ZFCP_STATUS_FSFREQ_ERROR; - zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1", req); + zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1"); } wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; @@ -1639,7 +1637,7 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1", req); + zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ACCESS_DENIED: @@ -1655,7 +1653,7 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) &sdev_to_zfcp(sdev)->status); zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ACCESS_BOXED); zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, - "fscpph2", req); + "fscpph2"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1744,7 +1742,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1", req); + zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1"); /* fall through */ case FSF_LUN_ALREADY_OPEN: break; @@ -1756,8 +1754,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) zfcp_erp_set_port_status(zfcp_sdev->port, ZFCP_STATUS_COMMON_ACCESS_BOXED); zfcp_erp_port_reopen(zfcp_sdev->port, - ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2", - req); + ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_SHARING_VIOLATION: @@ -1853,20 +1850,18 @@ static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1", - req); + zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_HANDLE_NOT_VALID: - zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2", req); + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: zfcp_erp_set_port_status(zfcp_sdev->port, ZFCP_STATUS_COMMON_ACCESS_BOXED); zfcp_erp_port_reopen(zfcp_sdev->port, - ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3", - req); + ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -2003,13 +1998,12 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_HANDLE_MISMATCH: case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1", - req); + zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_FCPLUN_NOT_VALID: case FSF_LUN_HANDLE_NOT_VALID: - zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2", req); + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: @@ -2027,7 +2021,7 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) (unsigned long long)zfcp_scsi_dev_lun(sdev), (unsigned long long)zfcp_sdev->port->wwpn); zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, - "fssfch3", req); + "fssfch3"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_CMND_LENGTH_NOT_VALID: @@ -2038,21 +2032,20 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) (unsigned long long)zfcp_scsi_dev_lun(sdev), (unsigned long long)zfcp_sdev->port->wwpn); zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, - "fssfch4", req); + "fssfch4"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: zfcp_erp_set_port_status(zfcp_sdev->port, ZFCP_STATUS_COMMON_ACCESS_BOXED); zfcp_erp_port_reopen(zfcp_sdev->port, - ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5", - req); + ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_BOXED: zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED); zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, - "fssfch6", req); + "fssfch6"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 434a33ba0509..d99c9dc9cfcb 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -41,7 +41,7 @@ static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id, zfcp_qdio_siosl(adapter); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | - ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL); + ZFCP_STATUS_COMMON_ERP_FAILED, id); } static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt) @@ -114,7 +114,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, * put SBALs back to response queue */ if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count)) - zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2", NULL); + zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2"); } static struct qdio_buffer_element * @@ -234,7 +234,7 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) if (!ret) { atomic_inc(&qdio->req_q_full); /* assume hanging outbound queue, try queue recovery */ - zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1", NULL); + zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1"); } spin_lock_irq(&qdio->req_q_lock); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 8c5c1c89c098..59a653d15a19 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -154,7 +154,7 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev) spin_lock_init(&zfcp_sdev->latencies.lock); zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING); - zfcp_erp_lun_reopen(sdev, 0, "scsla_1", NULL); + zfcp_erp_lun_reopen(sdev, 0, "scsla_1"); zfcp_erp_wait(port->adapter); return 0; @@ -278,7 +278,7 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; int ret; - zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt); + zfcp_erp_adapter_reopen(adapter, 0, "schrh_1"); zfcp_erp_wait(adapter); ret = fc_block_scsi_eh(scpnt); if (ret) @@ -516,7 +516,7 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) port = zfcp_get_port_by_wwpn(adapter, rport->port_name); if (port) { - zfcp_erp_port_forced_reopen(port, 0, "sctrpi1", NULL); + zfcp_erp_port_forced_reopen(port, 0, "sctrpi1"); put_device(&port->dev); } } diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 2f2c54f4718f..cdc4ff78a7ba 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -105,8 +105,7 @@ static ssize_t zfcp_sysfs_port_failed_store(struct device *dev, return -EINVAL; zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_RUNNING); - zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "sypfai2", - NULL); + zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "sypfai2"); zfcp_erp_wait(port->adapter); return count; @@ -148,7 +147,7 @@ static ssize_t zfcp_sysfs_unit_failed_store(struct device *dev, if (sdev) { zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, - "syufai2", NULL); + "syufai2"); zfcp_erp_wait(unit->port->adapter); } else zfcp_unit_scsi_scan(unit); @@ -198,7 +197,7 @@ static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev, zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, - "syafai2", NULL); + "syafai2"); zfcp_erp_wait(adapter); out: zfcp_ccw_adapter_put(adapter); @@ -256,7 +255,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, put_device(&port->dev); - zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL); + zfcp_erp_port_shutdown(port, 0, "syprs_1"); zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs); out: zfcp_ccw_adapter_put(adapter); -- cgit v1.2.3 From 3d63d3b4fb5fb3674f2d97725e187cbfa22562bc Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 2 Dec 2010 15:16:17 +0100 Subject: [SCSI] zfcp: Move qdio setup from erp to zfcp_qdio.c Initialization of the qdio waitqueue should happen when the qdio data is initialized and the QDIOUP flag should be handled in the qdio code as well. Adjust the code accordingly and remove the superfluos function zfcp_erp_adapter_strategy_open_qdio. Reviewed-by: Steffen Maier Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 13 +------------ drivers/s390/scsi/zfcp_qdio.c | 2 ++ 2 files changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 066f9ea67502..e003e306f870 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -644,17 +644,6 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) read_unlock_irqrestore(&adapter->erp_lock, flags); } -static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) -{ - struct zfcp_qdio *qdio = act->adapter->qdio; - - if (zfcp_qdio_open(qdio)) - return ZFCP_ERP_FAILED; - init_waitqueue_head(&qdio->req_q_wq); - atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status); - return ZFCP_ERP_SUCCEEDED; -} - static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) { struct zfcp_port *port; @@ -778,7 +767,7 @@ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act) { struct zfcp_adapter *adapter = act->adapter; - if (zfcp_erp_adapter_strategy_open_qdio(act)) { + if (zfcp_qdio_open(adapter->qdio)) { atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index d99c9dc9cfcb..2511f92302dd 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -307,6 +307,7 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio) return -ENOMEM; zfcp_qdio_setup_init_data(&init_data, qdio); + init_waitqueue_head(&qdio->req_q_wq); return qdio_allocate(&init_data); } @@ -391,6 +392,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) /* set index of first avalable SBALS / number of available SBALS */ qdio->req_q_idx = 0; atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q); + atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); return 0; -- cgit v1.2.3 From 51780d2c38a7294c2c302ae9d2ea517bd4153dec Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 2 Dec 2010 15:16:18 +0100 Subject: [SCSI] zfcp: Add __init declaration to zfcp_cache_hw_align The function zfcp_cache_hw_align is only called from zfcp_module_init, so it should be declared with __init as well. Reviewed-by: Steffen Maier Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 352ca0d4ca25..51c666fb67a4 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -45,8 +45,8 @@ static char *init_device; module_param_named(device, init_device, charp, 0400); MODULE_PARM_DESC(device, "specify initial device"); -static struct kmem_cache *zfcp_cache_hw_align(const char *name, - unsigned long size) +static struct kmem_cache * __init zfcp_cache_hw_align(const char *name, + unsigned long size) { return kmem_cache_create(name, size, roundup_pow_of_two(size), 0, NULL); } -- cgit v1.2.3 From 0d81b4e8dcc4177726f30a1ac8df1f726d2a7c0c Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 8 Dec 2010 17:30:46 +0100 Subject: [SCSI] zfcp: Add allow_lun_scan module parameter The zfcpdump tool requires a method to attach exactly one LUN. The easiest way to achieve this is to add a new zfcp module parameter. When allow_lun_scan is set to "false", zfcp only accepts LUNs that have been configured through the unit_add sysfs interface. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_scsi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 59a653d15a19..ddb5800823a9 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -30,6 +30,10 @@ module_param_named(dif, enable_dif, bool, 0600); MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support"); #endif +static bool allow_lun_scan = 1; +module_param(allow_lun_scan, bool, 0600); +MODULE_PARM_DESC(allow_lun_scan, "For NPIV, scan and attach all storage LUNs"); + static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason) { @@ -130,6 +134,7 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev) struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); struct zfcp_port *port; struct zfcp_unit *unit; + int npiv = adapter->connection_features & FSF_FEATURE_NPIV_MODE; port = zfcp_get_port_by_wwpn(adapter, rport->port_name); if (!port) @@ -139,7 +144,7 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev) if (unit) put_device(&unit->dev); - if (!unit && !(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) { + if (!unit && !(allow_lun_scan && npiv)) { put_device(&port->dev); return -ENXIO; } -- cgit v1.2.3 From 6dca467a76bb0ed71d65143b235e0ef80e44436f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 24 Dec 2010 16:00:18 +0100 Subject: s390: don't use flush_scheduled_work() flush_scheduled_work() is deprecated and scheduled to be removed. * tape_3590: Create and use tape_3590_wq instead of the system_wq. * tape_block: Directly flush requeue_task on cleanup instead of using flush_scheduled_work(). Signed-off-by: Tejun Heo Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Cc: linux-s390@vger.kernel.org --- drivers/s390/char/tape_3590.c | 18 +++++++++++++----- drivers/s390/char/tape_block.c | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index deff2c3361e4..fbe361fcd2c0 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -24,6 +24,8 @@ #include "tape_std.h" #include "tape_3590.h" +static struct workqueue_struct *tape_3590_wq; + /* * Pointer to debug area. */ @@ -613,7 +615,7 @@ tape_3590_schedule_work(struct tape_device *device, enum tape_op op) p->device = tape_get_device(device); p->op = op; - schedule_work(&p->work); + queue_work(tape_3590_wq, &p->work); return 0; } @@ -1629,7 +1631,7 @@ fail_kmalloc: static void tape_3590_cleanup_device(struct tape_device *device) { - flush_scheduled_work(); + flush_workqueue(tape_3590_wq); tape_std_unassign(device); kfree(device->discdata); @@ -1733,11 +1735,17 @@ tape_3590_init(void) #endif DBF_EVENT(3, "3590 init\n"); + + tape_3590_wq = alloc_workqueue("tape_3590", 0, 0); + if (!tape_3590_wq) + return -ENOMEM; + /* Register driver for 3590 tapes. */ rc = ccw_driver_register(&tape_3590_driver); - if (rc) + if (rc) { + destroy_workqueue(tape_3590_wq); DBF_EVENT(3, "3590 init failed\n"); - else + } else DBF_EVENT(3, "3590 registered\n"); return rc; } @@ -1746,7 +1754,7 @@ static void tape_3590_exit(void) { ccw_driver_unregister(&tape_3590_driver); - + destroy_workqueue(tape_3590_wq); debug_unregister(TAPE_DBF_AREA); } diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index f0fa9ca5cb2c..55d2d0f4eabc 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -264,7 +264,7 @@ cleanup_queue: void tapeblock_cleanup_device(struct tape_device *device) { - flush_scheduled_work(); + flush_work_sync(&device->blk_data.requeue_task); tape_put_device(device); if (!device->blk_data.disk) { -- cgit v1.2.3 From 53ec24b1e6c7118a127cf029a1519a2ce55268ec Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Wed, 5 Jan 2011 12:46:44 +0100 Subject: [S390] zcrypt: Fix check to look for facility bits 2 & 65 Fix the check for ap interupts to look for facility bits 2 and 65. Make sure that we only register interrupts for aps, if the machine has ap interrupt support. This patch is relevant only for the 2.6.37 stable series. Cc: stable@kernel.org Signed-off-by: Felix Beck Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 8fd8c62455e9..a1ba52a09602 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -154,7 +154,7 @@ static inline int ap_instructions_available(void) */ static int ap_interrupts_available(void) { - return test_facility(1) && test_facility(2); + return test_facility(2) && test_facility(65); } /** -- cgit v1.2.3 From 6f9a3c330652b0fdb65d89e94977a8e79fe730e7 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 5 Jan 2011 12:47:15 +0100 Subject: [S390] cleanup s390 Kconfig Make use of def_bool and def_tristate where possible and add sensible defaults to the config symbols where applicable. This shortens the defconfig file by another ~40 lines. Signed-off-by: Martin Schwidefsky --- arch/s390/Kconfig | 129 ++++++++++++++++++++------------------ arch/s390/Kconfig.debug | 6 +- arch/s390/defconfig | 152 +++++++++++++++++---------------------------- arch/s390/kvm/Kconfig | 7 ++- drivers/s390/block/Kconfig | 24 ++++--- drivers/s390/char/Kconfig | 69 ++++++++++++-------- drivers/s390/net/Kconfig | 51 ++++++++------- 7 files changed, 218 insertions(+), 220 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index e0b98e71ff47..3243f7a52c72 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -1,13 +1,8 @@ -config SCHED_MC - def_bool y - depends on SMP - config MMU def_bool y config ZONE_DMA - def_bool y - depends on 64BIT + def_bool y if 64BIT config LOCKDEP_SUPPORT def_bool y @@ -25,12 +20,10 @@ config RWSEM_XCHGADD_ALGORITHM def_bool y config ARCH_HAS_ILOG2_U32 - bool - default n + def_bool n config ARCH_HAS_ILOG2_U64 - bool - default n + def_bool n config GENERIC_HWEIGHT def_bool y @@ -42,9 +35,7 @@ config GENERIC_CLOCKEVENTS def_bool y config GENERIC_BUG - bool - depends on BUG - default y + def_bool y if BUG config GENERIC_BUG_RELATIVE_POINTERS def_bool y @@ -59,13 +50,10 @@ config ARCH_DMA_ADDR_T_64BIT def_bool 64BIT config GENERIC_LOCKBREAK - bool - default y - depends on SMP && PREEMPT + def_bool y if SMP && PREEMPT config PGSTE - bool - default y if KVM + def_bool y if KVM config VIRT_CPU_ACCOUNTING def_bool y @@ -129,8 +117,7 @@ config S390 select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE config SCHED_OMIT_FRAME_POINTER - bool - default y + def_bool y source "init/Kconfig" @@ -143,20 +130,21 @@ comment "Processor type and features" source "kernel/time/Kconfig" config 64BIT - bool "64 bit kernel" + def_bool y + prompt "64 bit kernel" help Select this option if you have an IBM z/Architecture machine and want to use the 64 bit addressing mode. config 32BIT - bool - default y if !64BIT + def_bool y if !64BIT config KTIME_SCALAR def_bool 32BIT config SMP - bool "Symmetric multi-processing support" + def_bool y + prompt "Symmetric multi-processing support" ---help--- This enables support for systems with more than one CPU. If you have a system with only one CPU, like most personal computers, say N. If @@ -188,10 +176,10 @@ config NR_CPUS approximately sixteen kilobytes to the kernel image. config HOTPLUG_CPU - bool "Support for hot-pluggable CPUs" + def_bool y + prompt "Support for hot-pluggable CPUs" depends on SMP select HOTPLUG - default n help Say Y here to be able to turn CPUs off and on. CPUs can be controlled through /sys/devices/system/cpu/cpu#. @@ -207,14 +195,16 @@ config SCHED_MC increased overhead in some places. config SCHED_BOOK - bool "Book scheduler support" + def_bool y + prompt "Book scheduler support" depends on SMP && SCHED_MC help Book scheduler support improves the CPU scheduler's decision making when dealing with machines that have several books. config MATHEMU - bool "IEEE FPU emulation" + def_bool y + prompt "IEEE FPU emulation" depends on MARCH_G5 help This option is required for IEEE compliant floating point arithmetic @@ -222,7 +212,8 @@ config MATHEMU need this. config COMPAT - bool "Kernel support for 31 bit emulation" + def_bool y + prompt "Kernel support for 31 bit emulation" depends on 64BIT select COMPAT_BINFMT_ELF help @@ -232,16 +223,14 @@ config COMPAT executing 31 bit applications. It is safe to say "Y". config SYSVIPC_COMPAT - bool - depends on COMPAT && SYSVIPC - default y + def_bool y if COMPAT && SYSVIPC config AUDIT_ARCH - bool - default y + def_bool y config S390_EXEC_PROTECT - bool "Data execute protection" + def_bool y + prompt "Data execute protection" help This option allows to enable a buffer overflow protection for user space programs and it also selects the addressing mode option above. @@ -301,7 +290,8 @@ config MARCH_Z196 endchoice config PACK_STACK - bool "Pack kernel stack" + def_bool y + prompt "Pack kernel stack" help This option enables the compiler option -mkernel-backchain if it is available. If the option is available the compiler supports @@ -314,7 +304,8 @@ config PACK_STACK Say Y if you are unsure. config SMALL_STACK - bool "Use 8kb for kernel stack instead of 16kb" + def_bool n + prompt "Use 8kb for kernel stack instead of 16kb" depends on PACK_STACK && 64BIT && !LOCKDEP help If you say Y here and the compiler supports the -mkernel-backchain @@ -326,7 +317,8 @@ config SMALL_STACK Say N if you are unsure. config CHECK_STACK - bool "Detect kernel stack overflow" + def_bool y + prompt "Detect kernel stack overflow" help This option enables the compiler option -mstack-guard and -mstack-size if they are available. If the compiler supports them @@ -350,7 +342,8 @@ config STACK_GUARD 512 for 64 bit. config WARN_STACK - bool "Emit compiler warnings for function with broken stack usage" + def_bool n + prompt "Emit compiler warnings for function with broken stack usage" help This option enables the compiler options -mwarn-framesize and -mwarn-dynamicstack. If the compiler supports these options it @@ -385,24 +378,24 @@ config ARCH_SPARSEMEM_DEFAULT def_bool y config ARCH_SELECT_MEMORY_MODEL - def_bool y + def_bool y config ARCH_ENABLE_MEMORY_HOTPLUG - def_bool y - depends on SPARSEMEM + def_bool y if SPARSEMEM config ARCH_ENABLE_MEMORY_HOTREMOVE def_bool y config ARCH_HIBERNATION_POSSIBLE - def_bool y if 64BIT + def_bool y if 64BIT source "mm/Kconfig" comment "I/O subsystem configuration" config QDIO - tristate "QDIO support" + def_tristate y + prompt "QDIO support" ---help--- This driver provides the Queued Direct I/O base support for IBM System z. @@ -413,7 +406,8 @@ config QDIO If unsure, say Y. config CHSC_SCH - tristate "Support for CHSC subchannels" + def_tristate y + prompt "Support for CHSC subchannels" help This driver allows usage of CHSC subchannels. A CHSC subchannel is usually present on LPAR only. @@ -431,7 +425,8 @@ config CHSC_SCH comment "Misc" config IPL - bool "Builtin IPL record support" + def_bool y + prompt "Builtin IPL record support" help If you want to use the produced kernel to IPL directly from a device, you have to merge a bootsector specific to the device @@ -463,7 +458,8 @@ config FORCE_MAX_ZONEORDER default "9" config PFAULT - bool "Pseudo page fault support" + def_bool y + prompt "Pseudo page fault support" help Select this option, if you want to use PFAULT pseudo page fault handling under VM. If running native or in LPAR, this option @@ -475,7 +471,8 @@ config PFAULT this option. config SHARED_KERNEL - bool "VM shared kernel support" + def_bool y + prompt "VM shared kernel support" help Select this option, if you want to share the text segment of the Linux kernel between different VM guests. This reduces memory @@ -486,7 +483,8 @@ config SHARED_KERNEL doing and want to exploit this feature. config CMM - tristate "Cooperative memory management" + def_tristate n + prompt "Cooperative memory management" help Select this option, if you want to enable the kernel interface to reduce the memory size of the system. This is accomplished @@ -498,14 +496,16 @@ config CMM option. config CMM_IUCV - bool "IUCV special message interface to cooperative memory management" + def_bool y + prompt "IUCV special message interface to cooperative memory management" depends on CMM && (SMSGIUCV=y || CMM=SMSGIUCV) help Select this option to enable the special message interface to the cooperative memory management. config APPLDATA_BASE - bool "Linux - VM Monitor Stream, base infrastructure" + def_bool n + prompt "Linux - VM Monitor Stream, base infrastructure" depends on PROC_FS help This provides a kernel interface for creating and updating z/VM APPLDATA @@ -520,7 +520,8 @@ config APPLDATA_BASE The /proc entries can also be read from, showing the current settings. config APPLDATA_MEM - tristate "Monitor memory management statistics" + def_tristate m + prompt "Monitor memory management statistics" depends on APPLDATA_BASE && VM_EVENT_COUNTERS help This provides memory management related data to the Linux - VM Monitor @@ -536,7 +537,8 @@ config APPLDATA_MEM appldata_mem.o. config APPLDATA_OS - tristate "Monitor OS statistics" + def_tristate m + prompt "Monitor OS statistics" depends on APPLDATA_BASE help This provides OS related data to the Linux - VM Monitor Stream, like @@ -550,7 +552,8 @@ config APPLDATA_OS appldata_os.o. config APPLDATA_NET_SUM - tristate "Monitor overall network statistics" + def_tristate m + prompt "Monitor overall network statistics" depends on APPLDATA_BASE && NET help This provides network related data to the Linux - VM Monitor Stream, @@ -567,30 +570,32 @@ config APPLDATA_NET_SUM source kernel/Kconfig.hz config S390_HYPFS_FS - bool "s390 hypervisor file system support" + def_bool y + prompt "s390 hypervisor file system support" select SYS_HYPERVISOR - default y help This is a virtual file system intended to provide accounting information in an s390 hypervisor environment. config KEXEC - bool "kexec system call" + def_bool n + prompt "kexec system call" help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot but is independent of hardware/microcode support. config ZFCPDUMP - bool "zfcpdump support" + def_bool n + prompt "zfcpdump support" select SMP - default n help Select this option if you want to build an zfcpdump enabled kernel. Refer to for more details on this. config S390_GUEST -bool "s390 guest support for KVM (EXPERIMENTAL)" + def_bool y + prompt "s390 guest support for KVM (EXPERIMENTAL)" depends on 64BIT && EXPERIMENTAL select VIRTIO select VIRTIO_RING @@ -602,9 +607,9 @@ bool "s390 guest support for KVM (EXPERIMENTAL)" the default console. config SECCOMP - bool "Enable seccomp to safely compute untrusted bytecode" + def_bool y + prompt "Enable seccomp to safely compute untrusted bytecode" depends on PROC_FS - default y help This kernel feature is useful for number crunching applications that may need to compute untrusted bytecode during their diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug index 05221b13ffb1..2b380df95606 100644 --- a/arch/s390/Kconfig.debug +++ b/arch/s390/Kconfig.debug @@ -1,8 +1,7 @@ menu "Kernel hacking" config TRACE_IRQFLAGS_SUPPORT - bool - default y + def_bool y source "lib/Kconfig.debug" @@ -19,7 +18,8 @@ config STRICT_DEVMEM If you are unsure, say Y. config DEBUG_STRICT_USER_COPY_CHECKS - bool "Strict user copy size checks" + def_bool n + prompt "Strict user copy size checks" ---help--- Enabling this option turns a certain set of sanity checks for user copy operations into compile time warnings. diff --git a/arch/s390/defconfig b/arch/s390/defconfig index e40ac6ee6526..d79697157ac0 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -2,16 +2,12 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_AUDIT=y +CONFIG_RCU_TRACE=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y -CONFIG_CGROUPS=y -CONFIG_CGROUP_NS=y -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_UTS_NS=y -CONFIG_IPC_NS=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -# CONFIG_COMPAT_BRK is not set +CONFIG_PERF_EVENTS=y CONFIG_SLAB=y CONFIG_KPROBES=y CONFIG_MODULES=y @@ -20,24 +16,12 @@ CONFIG_MODVERSIONS=y CONFIG_DEFAULT_DEADLINE=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y -CONFIG_64BIT=y -CONFIG_SMP=y -CONFIG_NR_CPUS=32 -CONFIG_COMPAT=y -CONFIG_S390_EXEC_PROTECT=y -CONFIG_PACK_STACK=y -CONFIG_CHECK_STACK=y CONFIG_PREEMPT=y CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTREMOVE=y -CONFIG_QDIO=y -CONFIG_CHSC_SCH=m -CONFIG_IPL=y CONFIG_BINFMT_MISC=m -CONFIG_PFAULT=y CONFIG_HZ_100=y CONFIG_KEXEC=y -CONFIG_S390_GUEST=y CONFIG_PM=y CONFIG_HIBERNATION=y CONFIG_PACKET=y @@ -46,16 +30,15 @@ CONFIG_NET_KEY=y CONFIG_AFIUCV=m CONFIG_INET=y CONFIG_IP_MULTICAST=y +# CONFIG_INET_LRO is not set CONFIG_IPV6=y -CONFIG_NETFILTER=y -CONFIG_NETFILTER_NETLINK_QUEUE=m -CONFIG_NETFILTER_NETLINK_LOG=m -CONFIG_NF_CONNTRACK=m -# CONFIG_NF_CT_PROTO_SCTP is not set +CONFIG_NET_SCTPPROBE=m +CONFIG_L2TP=m +CONFIG_L2TP_DEBUGFS=m +CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_PRIO=m -CONFIG_NET_SCH_MULTIQ=y CONFIG_NET_SCH_RED=m CONFIG_NET_SCH_SFQ=m CONFIG_NET_SCH_TEQL=m @@ -69,28 +52,14 @@ CONFIG_NET_CLS_U32=m CONFIG_CLS_U32_MARK=y CONFIG_NET_CLS_RSVP=m CONFIG_NET_CLS_RSVP6=m -CONFIG_NET_CLS_FLOW=m CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_POLICE=y -CONFIG_NET_ACT_NAT=m -CONFIG_CAN=m -CONFIG_CAN_RAW=m -CONFIG_CAN_BCM=m -CONFIG_CAN_VCAN=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_XIP=y -CONFIG_BLK_DEV_XPRAM=m -CONFIG_DASD=y -CONFIG_DASD_PROFILE=y -CONFIG_DASD_ECKD=y -CONFIG_DASD_FBA=y -CONFIG_DASD_DIAG=y -CONFIG_DASD_EER=y -CONFIG_VIRTIO_BLK=m +CONFIG_VIRTIO_BLK=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y @@ -102,101 +71,92 @@ CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y CONFIG_ZFCP=y -CONFIG_SCSI_DH=m -CONFIG_SCSI_DH_RDAC=m -CONFIG_SCSI_DH_HP_SW=m -CONFIG_SCSI_DH_EMC=m -CONFIG_SCSI_DH_ALUA=m -CONFIG_SCSI_OSD_INITIATOR=m -CONFIG_SCSI_OSD_ULD=m -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=m -CONFIG_MD_RAID0=m -CONFIG_MD_RAID1=m -CONFIG_MD_MULTIPATH=m -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_SNAPSHOT=y -CONFIG_DM_MIRROR=y -CONFIG_DM_ZERO=y -CONFIG_DM_MULTIPATH=m +CONFIG_ZFCP_DIF=y CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_BONDING=m CONFIG_EQUALIZER=m CONFIG_TUN=m -CONFIG_VETH=m CONFIG_NET_ETHERNET=y -CONFIG_LCS=m -CONFIG_CTCM=m -CONFIG_QETH=y -CONFIG_QETH_L2=y -CONFIG_QETH_L3=y -CONFIG_VIRTIO_NET=m -CONFIG_HW_RANDOM_VIRTIO=m +CONFIG_VIRTIO_NET=y CONFIG_RAW_DRIVER=m -CONFIG_TN3270=y -CONFIG_TN3270_TTY=y -CONFIG_TN3270_FS=m -CONFIG_TN3270_CONSOLE=y -CONFIG_TN3215=y -CONFIG_TN3215_CONSOLE=y -CONFIG_SCLP_TTY=y -CONFIG_SCLP_CONSOLE=y -CONFIG_SCLP_VT220_TTY=y -CONFIG_SCLP_VT220_CONSOLE=y -CONFIG_SCLP_CPI=m -CONFIG_SCLP_ASYNC=m -CONFIG_S390_TAPE=m -CONFIG_S390_TAPE_BLOCK=y -CONFIG_S390_TAPE_34XX=m -CONFIG_ACCESSIBILITY=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_NFSD=y -CONFIG_NFSD_V3=y +# CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_PARTITION_ADVANCED=y CONFIG_IBM_PARTITION=y CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y -# CONFIG_SCHED_DEBUG is not set -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_MUTEXES=y +CONFIG_TIMER_STATS=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_LOCK_STAT=y +CONFIG_DEBUG_LOCKDEP=y CONFIG_DEBUG_SPINLOCK_SLEEP=y +CONFIG_DEBUG_LIST=y +CONFIG_DEBUG_NOTIFIERS=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y +CONFIG_KPROBES_SANITY_TEST=y +CONFIG_CPU_NOTIFIER_ERROR_INJECT=m +CONFIG_LATENCYTOP=y CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_SAMPLES=y -CONFIG_CRYPTO_FIPS=y +CONFIG_DEBUG_PAGEALLOC=y +# CONFIG_FTRACE is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m +CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_CTS=m CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m CONFIG_CRYPTO_RMD256=m CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_KHAZAD=m CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_DEFLATE=m CONFIG_CRYPTO_ZLIB=m CONFIG_CRYPTO_LZO=m CONFIG_ZCRYPT=m +CONFIG_CRYPTO_SHA1_S390=m +CONFIG_CRYPTO_SHA256_S390=m CONFIG_CRYPTO_SHA512_S390=m -CONFIG_CRC_T10DIF=y -CONFIG_CRC32=m +CONFIG_CRYPTO_DES_S390=m +CONFIG_CRYPTO_AES_S390=m CONFIG_CRC7=m -CONFIG_KVM=m -CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_BALLOON=y diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index a7251580891c..f66a1bdbb61d 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -4,8 +4,8 @@ source "virt/kvm/Kconfig" menuconfig VIRTUALIZATION - bool "Virtualization" - default y + def_bool y + prompt "Virtualization" ---help--- Say Y here to get to see options for using your Linux host to run other operating systems inside virtual machines (guests). @@ -16,7 +16,8 @@ menuconfig VIRTUALIZATION if VIRTUALIZATION config KVM - tristate "Kernel-based Virtual Machine (KVM) support" + def_tristate y + prompt "Kernel-based Virtual Machine (KVM) support" depends on HAVE_KVM && EXPERIMENTAL select PREEMPT_NOTIFIERS select ANON_INODES diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index 07883197f474..8e477bb1f3f6 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig @@ -2,7 +2,8 @@ comment "S/390 block device drivers" depends on S390 && BLOCK config BLK_DEV_XPRAM - tristate "XPRAM disk support" + def_tristate m + prompt "XPRAM disk support" depends on S390 && BLOCK help Select this option if you want to use your expanded storage on S/390 @@ -12,13 +13,15 @@ config BLK_DEV_XPRAM xpram. If unsure, say "N". config DCSSBLK - tristate "DCSSBLK support" + def_tristate m + prompt "DCSSBLK support" depends on S390 && BLOCK help Support for dcss block device config DASD - tristate "Support for DASD devices" + def_tristate y + prompt "Support for DASD devices" depends on CCW && BLOCK select IOSCHED_DEADLINE help @@ -27,28 +30,32 @@ config DASD natively on a single image or an LPAR. config DASD_PROFILE - bool "Profiling support for dasd devices" + def_bool y + prompt "Profiling support for dasd devices" depends on DASD help Enable this option if you want to see profiling information in /proc/dasd/statistics. config DASD_ECKD - tristate "Support for ECKD Disks" + def_tristate y + prompt "Support for ECKD Disks" depends on DASD help ECKD devices are the most commonly used devices. You should enable this option unless you are very sure to have no ECKD device. config DASD_FBA - tristate "Support for FBA Disks" + def_tristate y + prompt "Support for FBA Disks" depends on DASD help Select this option to be able to access FBA devices. It is safe to say "Y". config DASD_DIAG - tristate "Support for DIAG access to Disks" + def_tristate y + prompt "Support for DIAG access to Disks" depends on DASD help Select this option if you want to use Diagnose250 command to access @@ -56,7 +63,8 @@ config DASD_DIAG say "N". config DASD_EER - bool "Extended error reporting (EER)" + def_bool y + prompt "Extended error reporting (EER)" depends on DASD help This driver provides a character device interface to the diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index 40834f18754c..dcee3c5c8954 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -2,76 +2,85 @@ comment "S/390 character device drivers" depends on S390 config TN3270 - tristate "Support for locally attached 3270 terminals" + def_tristate y + prompt "Support for locally attached 3270 terminals" depends on CCW help Include support for IBM 3270 terminals. config TN3270_TTY - tristate "Support for tty input/output on 3270 terminals" + def_tristate y + prompt "Support for tty input/output on 3270 terminals" depends on TN3270 help Include support for using an IBM 3270 terminal as a Linux tty. config TN3270_FS - tristate "Support for fullscreen applications on 3270 terminals" + def_tristate m + prompt "Support for fullscreen applications on 3270 terminals" depends on TN3270 help Include support for fullscreen applications on an IBM 3270 terminal. config TN3270_CONSOLE - bool "Support for console on 3270 terminal" + def_bool y + prompt "Support for console on 3270 terminal" depends on TN3270=y && TN3270_TTY=y help Include support for using an IBM 3270 terminal as a Linux system console. Available only if 3270 support is compiled in statically. config TN3215 - bool "Support for 3215 line mode terminal" + def_bool y + prompt "Support for 3215 line mode terminal" depends on CCW help Include support for IBM 3215 line-mode terminals. config TN3215_CONSOLE - bool "Support for console on 3215 line mode terminal" + def_bool y + prompt "Support for console on 3215 line mode terminal" depends on TN3215 help Include support for using an IBM 3215 line-mode terminal as a Linux system console. config CCW_CONSOLE - bool - depends on TN3215_CONSOLE || TN3270_CONSOLE - default y + def_bool y if TN3215_CONSOLE || TN3270_CONSOLE config SCLP_TTY - bool "Support for SCLP line mode terminal" + def_bool y + prompt "Support for SCLP line mode terminal" depends on S390 help Include support for IBM SCLP line-mode terminals. config SCLP_CONSOLE - bool "Support for console on SCLP line mode terminal" + def_bool y + prompt "Support for console on SCLP line mode terminal" depends on SCLP_TTY help Include support for using an IBM HWC line-mode terminal as the Linux system console. config SCLP_VT220_TTY - bool "Support for SCLP VT220-compatible terminal" + def_bool y + prompt "Support for SCLP VT220-compatible terminal" depends on S390 help Include support for an IBM SCLP VT220-compatible terminal. config SCLP_VT220_CONSOLE - bool "Support for console on SCLP VT220-compatible terminal" + def_bool y + prompt "Support for console on SCLP VT220-compatible terminal" depends on SCLP_VT220_TTY help Include support for using an IBM SCLP VT220-compatible terminal as a Linux system console. config SCLP_CPI - tristate "Control-Program Identification" + def_tristate m + prompt "Control-Program Identification" depends on S390 help This option enables the hardware console interface for system @@ -83,7 +92,8 @@ config SCLP_CPI need this feature and intend to run your kernel in LPAR. config SCLP_ASYNC - tristate "Support for Call Home via Asynchronous SCLP Records" + def_tristate m + prompt "Support for Call Home via Asynchronous SCLP Records" depends on S390 help This option enables the call home function, which is able to inform @@ -93,7 +103,8 @@ config SCLP_ASYNC need this feature and intend to run your kernel in LPAR. config S390_TAPE - tristate "S/390 tape device support" + def_tristate m + prompt "S/390 tape device support" depends on CCW help Select this option if you want to access channel-attached tape @@ -109,7 +120,8 @@ comment "S/390 tape interface support" depends on S390_TAPE config S390_TAPE_BLOCK - bool "Support for tape block devices" + def_bool y + prompt "Support for tape block devices" depends on S390_TAPE && BLOCK help Select this option if you want to access your channel-attached tape @@ -123,7 +135,8 @@ comment "S/390 tape hardware support" depends on S390_TAPE config S390_TAPE_34XX - tristate "Support for 3480/3490 tape hardware" + def_tristate m + prompt "Support for 3480/3490 tape hardware" depends on S390_TAPE help Select this option if you want to access IBM 3480/3490 magnetic @@ -131,7 +144,8 @@ config S390_TAPE_34XX It is safe to say "Y" here. config S390_TAPE_3590 - tristate "Support for 3590 tape hardware" + def_tristate m + prompt "Support for 3590 tape hardware" depends on S390_TAPE help Select this option if you want to access IBM 3590 magnetic @@ -139,7 +153,8 @@ config S390_TAPE_3590 It is safe to say "Y" here. config VMLOGRDR - tristate "Support for the z/VM recording system services (VM only)" + def_tristate m + prompt "Support for the z/VM recording system services (VM only)" depends on IUCV help Select this option if you want to be able to receive records collected @@ -148,29 +163,31 @@ config VMLOGRDR This driver depends on the IUCV support driver. config VMCP - bool "Support for the z/VM CP interface" + def_bool y + prompt "Support for the z/VM CP interface" depends on S390 help Select this option if you want to be able to interact with the control program on z/VM config MONREADER - tristate "API for reading z/VM monitor service records" + def_tristate m + prompt "API for reading z/VM monitor service records" depends on IUCV help Character device driver for reading z/VM monitor service records config MONWRITER - tristate "API for writing z/VM monitor service records" + def_tristate m + prompt "API for writing z/VM monitor service records" depends on S390 - default "m" help Character device driver for writing z/VM monitor service records config S390_VMUR - tristate "z/VM unit record device driver" + def_tristate m + prompt "z/VM unit record device driver" depends on S390 - default "m" help Character device driver for z/VM reader, puncher and printer. diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index 456b18743397..fa80ba1f0344 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -2,7 +2,8 @@ menu "S/390 network device drivers" depends on NETDEVICES && S390 config LCS - tristate "Lan Channel Station Interface" + def_tristate m + prompt "Lan Channel Station Interface" depends on CCW && NETDEVICES && (NET_ETHERNET || TR || FDDI) help Select this option if you want to use LCS networking on IBM System z. @@ -12,7 +13,8 @@ config LCS If you do not know what it is, it's safe to choose Y. config CTCM - tristate "CTC and MPC SNA device support" + def_tristate m + prompt "CTC and MPC SNA device support" depends on CCW && NETDEVICES help Select this option if you want to use channel-to-channel @@ -26,7 +28,8 @@ config CTCM If you do not need any channel-to-channel connection, choose N. config NETIUCV - tristate "IUCV network device support (VM only)" + def_tristate m + prompt "IUCV network device support (VM only)" depends on IUCV && NETDEVICES help Select this option if you want to use inter-user communication @@ -37,14 +40,16 @@ config NETIUCV The module name is netiucv. If unsure, choose Y. config SMSGIUCV - tristate "IUCV special message support (VM only)" + def_tristate m + prompt "IUCV special message support (VM only)" depends on IUCV help Select this option if you want to be able to receive SMSG messages from other VM guest systems. config SMSGIUCV_EVENT - tristate "Deliver IUCV special messages as uevents (VM only)" + def_tristate m + prompt "Deliver IUCV special messages as uevents (VM only)" depends on SMSGIUCV help Select this option to deliver CP special messages (SMSGs) as @@ -54,7 +59,8 @@ config SMSGIUCV_EVENT To compile as a module, choose M. The module name is "smsgiucv_app". config CLAW - tristate "CLAW device support" + def_tristate m + prompt "CLAW device support" depends on CCW && NETDEVICES help This driver supports channel attached CLAW devices. @@ -64,7 +70,8 @@ config CLAW To compile into the kernel, choose Y. config QETH - tristate "Gigabit Ethernet device support" + def_tristate y + prompt "Gigabit Ethernet device support" depends on CCW && NETDEVICES && IP_MULTICAST && QDIO help This driver supports the IBM System z OSA Express adapters @@ -78,25 +85,25 @@ config QETH The module name is qeth. config QETH_L2 - tristate "qeth layer 2 device support" - depends on QETH - help - Select this option to be able to run qeth devices in layer 2 mode. - To compile as a module, choose M. The module name is qeth_l2. - If unsure, choose y. + def_tristate y + prompt "qeth layer 2 device support" + depends on QETH + help + Select this option to be able to run qeth devices in layer 2 mode. + To compile as a module, choose M. The module name is qeth_l2. + If unsure, choose y. config QETH_L3 - tristate "qeth layer 3 device support" - depends on QETH - help - Select this option to be able to run qeth devices in layer 3 mode. - To compile as a module choose M. The module name is qeth_l3. - If unsure, choose Y. + def_tristate y + prompt "qeth layer 3 device support" + depends on QETH + help + Select this option to be able to run qeth devices in layer 3 mode. + To compile as a module choose M. The module name is qeth_l3. + If unsure, choose Y. config QETH_IPV6 - bool - depends on (QETH_L3 = IPV6) || (QETH_L3 && IPV6 = 'y') - default y + def_bool y if (QETH_L3 = IPV6) || (QETH_L3 && IPV6 = 'y') config CCWGROUP tristate -- cgit v1.2.3 From 052ff461c8427629aee887ccc27478fc7373237c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 5 Jan 2011 12:47:28 +0100 Subject: [S390] irq: have detailed statistics for interrupt types Up to now /proc/interrupts only has statistics for external and i/o interrupts but doesn't split up them any further. This patch adds a line for every single interrupt source so that it is possible to easier tell what the machine is/was doing. Part of the output now looks like this; CPU0 CPU2 CPU4 EXT: 3898 4232 2305 I/O: 782 315 245 CLK: 1029 1964 727 [EXT] Clock Comparator IPI: 2868 2267 1577 [EXT] Signal Processor TMR: 0 0 0 [EXT] CPU Timer TAL: 0 0 0 [EXT] Timing Alert PFL: 0 0 0 [EXT] Pseudo Page Fault [...] NMI: 0 1 1 [NMI] Machine Checks Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 23 +++++++++++------------ arch/s390/kernel/irq.c | 30 ++++++++++++++++++++++++------ arch/s390/kernel/nmi.c | 3 ++- arch/s390/kernel/smp.c | 1 + arch/s390/kernel/time.c | 3 +++ arch/s390/kernel/vtime.c | 1 + arch/s390/mm/fault.c | 2 ++ drivers/s390/block/dasd_diag.c | 2 ++ drivers/s390/char/sclp.c | 6 +++++- drivers/s390/kvm/kvm_virtio.c | 3 +++ net/iucv/iucv.c | 2 ++ 11 files changed, 56 insertions(+), 20 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index 7da991a858f8..f65faf63ab3a 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -1,23 +1,22 @@ #ifndef _ASM_IRQ_H #define _ASM_IRQ_H -#ifdef __KERNEL__ #include -/* - * the definition of irqs has changed in 2.5.46: - * NR_IRQS is no longer the number of i/o - * interrupts (65536), but rather the number - * of interrupt classes (2). - * Only external and i/o interrupts make much sense here (CH). - */ - enum interruption_class { EXTERNAL_INTERRUPT, IO_INTERRUPT, - + EXTINT_CLK, + EXTINT_IPI, + EXTINT_TMR, + EXTINT_TLA, + EXTINT_PFL, + EXTINT_DSD, + EXTINT_VRT, + EXTINT_SCP, + EXTINT_IUC, + NMI_NMI, NR_IRQS, }; -#endif /* __KERNEL__ */ -#endif +#endif /* _ASM_IRQ_H */ diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 026a37a94fc9..9bd049b8f997 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -1,7 +1,5 @@ /* - * arch/s390/kernel/irq.c - * - * Copyright IBM Corp. 2004,2007 + * Copyright IBM Corp. 2004,2010 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Thomas Spatzier (tspat@de.ibm.com) * @@ -17,12 +15,31 @@ #include #include +struct irq_class { + char *name; + char *desc; +}; + +static const struct irq_class intrclass_names[] = { + {.name = "EXT" }, + {.name = "I/O" }, + {.name = "CLK", .desc = "[EXT] Clock Comparator" }, + {.name = "IPI", .desc = "[EXT] Signal Processor" }, + {.name = "TMR", .desc = "[EXT] CPU Timer" }, + {.name = "TAL", .desc = "[EXT] Timing Alert" }, + {.name = "PFL", .desc = "[EXT] Pseudo Page Fault" }, + {.name = "DSD", .desc = "[EXT] DASD Diag" }, + {.name = "VRT", .desc = "[EXT] Virtio" }, + {.name = "SCP", .desc = "[EXT] Service Call" }, + {.name = "IUC", .desc = "[EXT] IUCV" }, + {.name = "NMI", .desc = "[NMI] Machine Check" }, +}; + /* * show_interrupts is needed by /proc/interrupts. */ int show_interrupts(struct seq_file *p, void *v) { - static const char *intrclass_names[] = { "EXT", "I/O", }; int i = *(loff_t *) v, j; get_online_cpus(); @@ -34,15 +51,16 @@ int show_interrupts(struct seq_file *p, void *v) } if (i < NR_IRQS) { - seq_printf(p, "%s: ", intrclass_names[i]); + seq_printf(p, "%s: ", intrclass_names[i].name); #ifndef CONFIG_SMP seq_printf(p, "%10u ", kstat_irqs(i)); #else for_each_online_cpu(j) seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif + if (intrclass_names[i].desc) + seq_printf(p, " %s", intrclass_names[i].desc); seq_putc(p, '\n'); - } put_online_cpus(); return 0; diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 1995c1712fc8..fab88431a06f 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -8,6 +8,7 @@ * Heiko Carstens , */ +#include #include #include #include @@ -255,7 +256,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs) nmi_enter(); s390_idle_check(regs, S390_lowcore.mcck_clock, S390_lowcore.mcck_enter_timer); - + kstat_cpu(smp_processor_id()).irqs[NMI_NMI]++; mci = (struct mci *) &S390_lowcore.mcck_interruption_code; mcck = &__get_cpu_var(cpu_mcck); umode = user_mode(regs); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 94cf510b8fe1..a9702df22f3a 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -161,6 +161,7 @@ static void do_ext_call_interrupt(unsigned int ext_int_code, { unsigned long bits; + kstat_cpu(smp_processor_id()).irqs[EXTINT_IPI]++; /* * handle bit signal external calls * diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 4c9d72d2e273..9e7b039458da 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -15,6 +15,7 @@ #define KMSG_COMPONENT "time" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include #include #include @@ -160,6 +161,7 @@ static void clock_comparator_interrupt(unsigned int ext_int_code, unsigned int param32, unsigned long param64) { + kstat_cpu(smp_processor_id()).irqs[EXTINT_CLK]++; if (S390_lowcore.clock_comparator == -1ULL) set_clock_comparator(S390_lowcore.clock_comparator); } @@ -170,6 +172,7 @@ static void stp_timing_alert(struct stp_irq_parm *); static void timing_alert_interrupt(unsigned int ext_int_code, unsigned int param32, unsigned long param64) { + kstat_cpu(smp_processor_id()).irqs[EXTINT_TLA]++; if (param32 & 0x00c40000) etr_timing_alert((struct etr_irq_parm *) ¶m32); if (param32 & 0x00038000) diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 8636dd00e393..1ccdf4d8aa85 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -324,6 +324,7 @@ static void do_cpu_timer_interrupt(unsigned int ext_int_code, struct list_head cb_list; /* the callback queue */ __u64 elapsed, next; + kstat_cpu(smp_processor_id()).irqs[EXTINT_TMR]++; INIT_LIST_HEAD(&cb_list); vq = &__get_cpu_var(virt_cpu_timer); diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index fe5701e9efbf..839b16df72b3 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -10,6 +10,7 @@ * Copyright (C) 1995 Linus Torvalds */ +#include #include #include #include @@ -543,6 +544,7 @@ static void pfault_interrupt(unsigned int ext_int_code, struct task_struct *tsk; __u16 subcode; + kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; /* * Get the external interruption subcode & pfault * initial/completion signal bit. VM stores this diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 266b34b55403..a3a5db58df18 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -10,6 +10,7 @@ #define KMSG_COMPONENT "dasd" +#include #include #include #include @@ -238,6 +239,7 @@ static void dasd_ext_handler(unsigned int ext_int_code, addr_t ip; int rc; + kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; switch (ext_int_code >> 24) { case DASD_DIAG_CODE_31BIT: ip = (addr_t) param32; diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 35cc4686b99b..e65572e504ba 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -7,6 +7,7 @@ * Martin Schwidefsky */ +#include #include #include #include @@ -18,8 +19,9 @@ #include #include #include -#include #include +#include +#include #include "sclp.h" @@ -402,6 +404,7 @@ static void sclp_interrupt_handler(unsigned int ext_int_code, u32 finished_sccb; u32 evbuf_pending; + kstat_cpu(smp_processor_id()).irqs[EXTINT_SCP]++; spin_lock(&sclp_lock); finished_sccb = param32 & 0xfffffff8; evbuf_pending = param32 & 0x3; @@ -824,6 +827,7 @@ static void sclp_check_handler(unsigned int ext_int_code, { u32 finished_sccb; + kstat_cpu(smp_processor_id()).irqs[EXTINT_SCP]++; finished_sccb = param32 & 0xfffffff8; /* Is this the interrupt we are waiting for? */ if (finished_sccb == 0) diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 375aeeaf9ea5..414427d64a8f 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -10,6 +10,7 @@ * Author(s): Christian Borntraeger */ +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #define VIRTIO_SUBCODE_64 0x0D00 @@ -379,6 +381,7 @@ static void kvm_extint_handler(unsigned int ext_int_code, u16 subcode; u32 param; + kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; subcode = ext_int_code >> 16; if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) return; diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index f7db676de77d..1ee5dab3cfae 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -36,6 +36,7 @@ #define KMSG_COMPONENT "iucv" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include #include #include @@ -1804,6 +1805,7 @@ static void iucv_external_interrupt(unsigned int ext_int_code, struct iucv_irq_data *p; struct iucv_irq_list *work; + kstat_cpu(smp_processor_id()).irqs[EXTINT_IUC]++; p = iucv_irq_data[smp_processor_id()]; if (p->ippathid >= iucv_max_pathid) { WARN_ON(p->ippathid >= iucv_max_pathid); -- cgit v1.2.3 From 30d77c3e1cbdff304b16ae02cb56baaa308e42fd Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 5 Jan 2011 12:47:29 +0100 Subject: [S390] qdio: add qdio interrupts to interrupt statistics Count traditional qdio interrupts and adapter interrupts for qdio in the interrupt statistics. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 2 ++ arch/s390/kernel/irq.c | 2 ++ drivers/s390/cio/qdio_main.c | 2 ++ drivers/s390/cio/qdio_thinint.c | 2 ++ 4 files changed, 8 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index f65faf63ab3a..28cfe5905a00 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -15,6 +15,8 @@ enum interruption_class { EXTINT_VRT, EXTINT_SCP, EXTINT_IUC, + IOINT_QAI, + IOINT_QDI, NMI_NMI, NR_IRQS, }; diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 9bd049b8f997..61d8098aa0b6 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -32,6 +32,8 @@ static const struct irq_class intrclass_names[] = { {.name = "VRT", .desc = "[EXT] Virtio" }, {.name = "SCP", .desc = "[EXT] Service Call" }, {.name = "IUC", .desc = "[EXT] IUCV" }, + {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, + {.name = "QDI", .desc = "[I/O] QDIO Interrupt" }, {.name = "NMI", .desc = "[NMI] Machine Check" }, }; diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 5fcfa7f9e9ef..194ea8c182b2 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -970,6 +971,7 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, return; } + kstat_cpu(smp_processor_id()).irqs[IOINT_QDI]++; if (irq_ptr->perf_stat_enabled) irq_ptr->perf_stat.qdio_int++; diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 5d9c66627b6e..64b59a58a1cd 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -8,6 +8,7 @@ */ #include #include +#include #include #include #include @@ -127,6 +128,7 @@ static void tiqdio_thinint_handler(void *alsi, void *data) struct qdio_q *q; last_ai_time = S390_lowcore.int_clock; + kstat_cpu(smp_processor_id()).irqs[IOINT_QAI]++; /* * SVS only when needed: issue SVS to benefit from iqdio interrupt -- cgit v1.2.3 From 3283942b71eb5023184b378230f5f0e3fbb40991 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 5 Jan 2011 12:47:30 +0100 Subject: [S390] dasd: add support for irq statistics Add support for DASD I/O interrupt statistics in /proc/interrupts. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 1 + arch/s390/kernel/irq.c | 1 + drivers/s390/block/dasd.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index 28cfe5905a00..082ef0cce287 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -17,6 +17,7 @@ enum interruption_class { EXTINT_IUC, IOINT_QAI, IOINT_QDI, + IOINT_DAS, NMI_NMI, NR_IRQS, }; diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 61d8098aa0b6..313fe83a443a 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -34,6 +34,7 @@ static const struct irq_class intrclass_names[] = { {.name = "IUC", .desc = "[EXT] IUCV" }, {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, {.name = "QDI", .desc = "[I/O] QDIO Interrupt" }, + {.name = "DAS", .desc = "[I/O] DASD" }, {.name = "NMI", .desc = "[NMI] Machine Check" }, }; diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index fb613d70c2cb..faa7d425cb9c 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -11,6 +11,7 @@ #define KMSG_COMPONENT "dasd" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include #include #include @@ -1076,6 +1077,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, unsigned long long now; int expires; + kstat_cpu(smp_processor_id()).irqs[IOINT_DAS]++; if (IS_ERR(irb)) { switch (PTR_ERR(irb)) { case -EIO: -- cgit v1.2.3 From 12fae5858cd97181c92472c9bb5f098a7eca2ffe Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 5 Jan 2011 12:47:31 +0100 Subject: [S390] 3215: add support for irq statistics Add support for 3215 I/O interrupt statistics in /proc/interrupts. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 1 + arch/s390/kernel/irq.c | 1 + drivers/s390/char/con3215.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index 082ef0cce287..d52533df6ac8 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -18,6 +18,7 @@ enum interruption_class { IOINT_QAI, IOINT_QDI, IOINT_DAS, + IOINT_C15, NMI_NMI, NR_IRQS, }; diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 313fe83a443a..e7914e4adc48 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -35,6 +35,7 @@ static const struct irq_class intrclass_names[] = { {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, {.name = "QDI", .desc = "[I/O] QDIO Interrupt" }, {.name = "DAS", .desc = "[I/O] DASD" }, + {.name = "C15", .desc = "[I/O] 3215" }, {.name = "NMI", .desc = "[NMI] Machine Check" }, }; diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 59ec073724bf..3fb4335d491d 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -9,6 +9,7 @@ * Dan Morrison, IBM Corporation */ +#include #include #include #include @@ -361,6 +362,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, int cstat, dstat; int count; + kstat_cpu(smp_processor_id()).irqs[IOINT_C15]++; raw = dev_get_drvdata(&cdev->dev); req = (struct raw3215_req *) intparm; cstat = irb->scsw.cmd.cstat; -- cgit v1.2.3 From 3fe22f6bfd6f81aafd140d69578d3a2c39674664 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 5 Jan 2011 12:47:32 +0100 Subject: [S390] 3270: add support for irq statistics Add support for 3270 I/O interrupt statistics in /proc/interrupts. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 1 + arch/s390/kernel/irq.c | 1 + drivers/s390/char/raw3270.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index d52533df6ac8..65e63c02b0f9 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -19,6 +19,7 @@ enum interruption_class { IOINT_QDI, IOINT_DAS, IOINT_C15, + IOINT_C70, NMI_NMI, NR_IRQS, }; diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index e7914e4adc48..8c241416576f 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -36,6 +36,7 @@ static const struct irq_class intrclass_names[] = { {.name = "QDI", .desc = "[I/O] QDIO Interrupt" }, {.name = "DAS", .desc = "[I/O] DASD" }, {.name = "C15", .desc = "[I/O] 3215" }, + {.name = "C70", .desc = "[I/O] 3270" }, {.name = "NMI", .desc = "[NMI] Machine Check" }, }; diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 2a4c566456e7..96ba2fd1c8ad 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -7,6 +7,7 @@ * Copyright IBM Corp. 2003, 2009 */ +#include #include #include #include @@ -329,6 +330,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) struct raw3270_request *rq; int rc; + kstat_cpu(smp_processor_id()).irqs[IOINT_C70]++; rp = dev_get_drvdata(&cdev->dev); if (!rp) return; -- cgit v1.2.3 From b86651721f18f40319efe94ed3eac2d26682e5b9 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 5 Jan 2011 12:47:33 +0100 Subject: [S390] tape: add support for irq statistics Add support for ccw based tape I/O interrupt statistics in /proc/interrupts. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 1 + arch/s390/kernel/irq.c | 1 + drivers/s390/char/tape_core.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index 65e63c02b0f9..6986343a566f 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -20,6 +20,7 @@ enum interruption_class { IOINT_DAS, IOINT_C15, IOINT_C70, + IOINT_TAP, NMI_NMI, NR_IRQS, }; diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 8c241416576f..5d7b6fbb3c13 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -37,6 +37,7 @@ static const struct irq_class intrclass_names[] = { {.name = "DAS", .desc = "[I/O] DASD" }, {.name = "C15", .desc = "[I/O] 3215" }, {.name = "C70", .desc = "[I/O] 3270" }, + {.name = "TAP", .desc = "[I/O] Tape" }, {.name = "NMI", .desc = "[NMI] Machine Check" }, }; diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index b3a3e8e8656e..7978a0adeaf3 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -14,6 +14,7 @@ #define KMSG_COMPONENT "tape" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include #include // for kernel parameters #include // for requesting modules @@ -1114,6 +1115,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) struct tape_request *request; int rc; + kstat_cpu(smp_processor_id()).irqs[IOINT_TAP]++; device = dev_get_drvdata(&cdev->dev); if (device == NULL) { return; -- cgit v1.2.3 From f48198d592b0d680b9677bd69edd2290cd0c1f4f Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 5 Jan 2011 12:47:34 +0100 Subject: [S390] vmur: add support for irq statistics Add support for VMUR I/O interrupt statistics in /proc/interrupts. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 1 + arch/s390/kernel/irq.c | 1 + drivers/s390/char/vmur.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index 6986343a566f..6c9b55681eab 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -21,6 +21,7 @@ enum interruption_class { IOINT_C15, IOINT_C70, IOINT_TAP, + IOINT_VMR, NMI_NMI, NR_IRQS, }; diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 5d7b6fbb3c13..ae726d1ae430 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -38,6 +38,7 @@ static const struct irq_class intrclass_names[] = { {.name = "C15", .desc = "[I/O] 3215" }, {.name = "C70", .desc = "[I/O] 3270" }, {.name = "TAP", .desc = "[I/O] Tape" }, + {.name = "VMR", .desc = "[I/O] Unit Record Devices" }, {.name = "NMI", .desc = "[NMI] Machine Check" }, }; diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index f7e4ae6bf15a..caef1757341d 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -11,6 +11,7 @@ #define KMSG_COMPONENT "vmur" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include #include @@ -302,6 +303,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, { struct urdev *urd; + kstat_cpu(smp_processor_id()).irqs[IOINT_VMR]++; TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n", intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, irb->scsw.cmd.count); -- cgit v1.2.3 From 096a61682e86090e4e74118ff6fa6858ca73aa58 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 5 Jan 2011 12:47:35 +0100 Subject: [S390] lcs: add support for irq statistics Add support for LCS I/O interrupt statistics in /proc/interrupts. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 1 + arch/s390/kernel/irq.c | 1 + drivers/s390/net/lcs.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index 6c9b55681eab..6a455b8ea18b 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -22,6 +22,7 @@ enum interruption_class { IOINT_C70, IOINT_TAP, IOINT_VMR, + IOINT_LCS, NMI_NMI, NR_IRQS, }; diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index ae726d1ae430..4c6e071b7f92 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -39,6 +39,7 @@ static const struct irq_class intrclass_names[] = { {.name = "C70", .desc = "[I/O] 3270" }, {.name = "TAP", .desc = "[I/O] Tape" }, {.name = "VMR", .desc = "[I/O] Unit Record Devices" }, + {.name = "LCS", .desc = "[I/O] LCS" }, {.name = "NMI", .desc = "[NMI] Machine Check" }, }; diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 0f19d540b655..0bf708944314 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -26,6 +26,7 @@ #define KMSG_COMPONENT "lcs" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include #include #include @@ -1396,6 +1397,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) int rc, index; int cstat, dstat; + kstat_cpu(smp_processor_id()).irqs[IOINT_LCS]++; if (lcs_check_irb_error(cdev, irb)) return; -- cgit v1.2.3 From 355eb4022b92349f70cd69ce5b9572c71c0be226 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 5 Jan 2011 12:47:36 +0100 Subject: [S390] claw: add support for irq statistics Add support for CLAW I/O interrupt statistics in /proc/interrupts. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 1 + arch/s390/kernel/irq.c | 1 + drivers/s390/net/claw.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index 6a455b8ea18b..2d5943c1c6a1 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -23,6 +23,7 @@ enum interruption_class { IOINT_TAP, IOINT_VMR, IOINT_LCS, + IOINT_CLW, NMI_NMI, NR_IRQS, }; diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 4c6e071b7f92..406b539f61a9 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -40,6 +40,7 @@ static const struct irq_class intrclass_names[] = { {.name = "TAP", .desc = "[I/O] Tape" }, {.name = "VMR", .desc = "[I/O] Unit Record Devices" }, {.name = "LCS", .desc = "[I/O] LCS" }, + {.name = "CLW", .desc = "[I/O] CLAW" }, {.name = "NMI", .desc = "[NMI] Machine Check" }, }; diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 8e4153d740f3..ce3a5c13ce0b 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -63,6 +63,7 @@ #define KMSG_COMPONENT "claw" +#include #include #include #include @@ -640,6 +641,7 @@ claw_irq_handler(struct ccw_device *cdev, struct claw_env *p_env; struct chbk *p_ch_r=NULL; + kstat_cpu(smp_processor_id()).irqs[IOINT_CLW]++; CLAW_DBF_TEXT(4, trace, "clawirq"); /* Bypass all 'unsolicited interrupts' */ privptr = dev_get_drvdata(&cdev->dev); -- cgit v1.2.3 From 85b81cdd0b038d580dedf6289df7de65826967d6 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 5 Jan 2011 12:47:37 +0100 Subject: [S390] ctc: add support for irq statistics Add support for CTC I/O interrupt statistics in /proc/interrupts. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 1 + arch/s390/kernel/irq.c | 1 + drivers/s390/net/ctcm_main.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index 2d5943c1c6a1..8c79f9400a36 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -24,6 +24,7 @@ enum interruption_class { IOINT_VMR, IOINT_LCS, IOINT_CLW, + IOINT_CTC, NMI_NMI, NR_IRQS, }; diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 406b539f61a9..57ed2b55c2a1 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -41,6 +41,7 @@ static const struct irq_class intrclass_names[] = { {.name = "VMR", .desc = "[I/O] Unit Record Devices" }, {.name = "LCS", .desc = "[I/O] LCS" }, {.name = "CLW", .desc = "[I/O] CLAW" }, + {.name = "CTC", .desc = "[I/O] CTC" }, {.name = "NMI", .desc = "[NMI] Machine Check" }, }; diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 2c7d2d9be4d0..4c2845985927 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -24,6 +24,7 @@ #define KMSG_COMPONENT "ctcm" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include #include #include @@ -1204,6 +1205,7 @@ static void ctcm_irq_handler(struct ccw_device *cdev, int cstat; int dstat; + kstat_cpu(smp_processor_id()).irqs[IOINT_CTC]++; CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, "Enter %s(%s)", CTCM_FUNTAIL, dev_name(&cdev->dev)); -- cgit v1.2.3 From 62d146ffe3adfed2747fc36138476c8417ce73a7 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 5 Jan 2011 12:47:38 +0100 Subject: [S390] ap bus: add support for irq statistics Add support for AP Bus I/O interrupt statistics in /proc/interrupts. Signed-off-by: Holger Dengler Signed-off-by: Felix Beck Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 1 + arch/s390/kernel/irq.c | 1 + drivers/s390/crypto/ap_bus.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index 8c79f9400a36..db14a311f1d2 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -25,6 +25,7 @@ enum interruption_class { IOINT_LCS, IOINT_CLW, IOINT_CTC, + IOINT_APB, NMI_NMI, NR_IRQS, }; diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 57ed2b55c2a1..ea5099c9709c 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -42,6 +42,7 @@ static const struct irq_class intrclass_names[] = { {.name = "LCS", .desc = "[I/O] LCS" }, {.name = "CLW", .desc = "[I/O] CLAW" }, {.name = "CTC", .desc = "[I/O] CTC" }, + {.name = "APB", .desc = "[I/O] AP Bus" }, {.name = "NMI", .desc = "[NMI] Machine Check" }, }; diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index a1ba52a09602..4f37c45ee114 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -27,6 +27,7 @@ #define KMSG_COMPONENT "ap" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include #include #include @@ -1042,6 +1043,7 @@ out: static void ap_interrupt_handler(void *unused1, void *unused2) { + kstat_cpu(smp_processor_id()).irqs[IOINT_APB]++; tasklet_schedule(&ap_tasklet); } -- cgit v1.2.3 From 98b799800c3e2f855ef2d2c6263e84fa5d1420a0 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 5 Jan 2011 12:47:40 +0100 Subject: [S390] sclp: use register_external_interrupt() Use register_external_interrupt() instead of register_early_external_interrupt(). The early variant is not necessary since kmalloc works already. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index e65572e504ba..b76c61f82485 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -27,9 +27,6 @@ #define SCLP_HEADER "sclp: " -/* Structure for register_early_external_interrupt. */ -static ext_int_info_t ext_int_info_hwc; - /* Lock to protect internal data consistency. */ static DEFINE_SPINLOCK(sclp_lock); @@ -870,8 +867,7 @@ sclp_check_interface(void) spin_lock_irqsave(&sclp_lock, flags); /* Prepare init mask command */ - rc = register_early_external_interrupt(0x2401, sclp_check_handler, - &ext_int_info_hwc); + rc = register_external_interrupt(0x2401, sclp_check_handler); if (rc) { spin_unlock_irqrestore(&sclp_lock, flags); return rc; @@ -904,8 +900,7 @@ sclp_check_interface(void) } else rc = -EBUSY; } - unregister_early_external_interrupt(0x2401, sclp_check_handler, - &ext_int_info_hwc); + unregister_external_interrupt(0x2401, sclp_check_handler); spin_unlock_irqrestore(&sclp_lock, flags); return rc; } @@ -1068,8 +1063,7 @@ sclp_init(void) if (rc) goto fail_init_state_uninitialized; /* Register interrupt handler */ - rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler, - &ext_int_info_hwc); + rc = register_external_interrupt(0x2401, sclp_interrupt_handler); if (rc) goto fail_unregister_reboot_notifier; sclp_init_state = sclp_init_state_initialized; -- cgit v1.2.3 From b1f933da570576d1f290ea4dc9b896404cbd285d Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Wed, 5 Jan 2011 12:47:44 +0100 Subject: [S390] zcrypt: Introduce check for 4096 bit support. Implemented an asm in the ap bus and made it accessible for the card specific parts of the zcrypt driver. Thus when a cex3a is recognized a check can be performed to dermine whether the card supports 4096 bit RSA keys. Signed-off-by: Felix Beck Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 63 ++++++++++++++++++++++++++++++++++++++++++++ drivers/s390/crypto/ap_bus.h | 2 ++ 2 files changed, 65 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 4f37c45ee114..67302b944ab3 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -222,6 +222,69 @@ ap_queue_interruption_control(ap_qid_t qid, void *ind) } #endif +static inline struct ap_queue_status __ap_4096_commands_available(ap_qid_t qid, + int *support) +{ + register unsigned long reg0 asm ("0") = 0UL | qid | (1UL << 23); + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm ("2") = 0UL; + + asm volatile( + ".long 0xb2af0000\n" + "0: la %1,0\n" + "1:\n" + EX_TABLE(0b, 1b) + : "+d" (reg0), "=d" (reg1), "=d" (reg2) + : + : "cc"); + + if (reg2 & 0x6000000000000000ULL) + *support = 1; + else + *support = 0; + + return reg1; +} + +/** + * ap_4096_commands_availablen(): Check for availability of 4096 bit RSA + * support. + * @qid: The AP queue number + * + * Returns 1 if 4096 bit RSA keys are support fo the AP, returns 0 if not. + */ +int ap_4096_commands_available(ap_qid_t qid) +{ + struct ap_queue_status status; + int i, support = 0; + status = __ap_4096_commands_available(qid, &support); + + for (i = 0; i < AP_MAX_RESET; i++) { + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + return support; + case AP_RESPONSE_RESET_IN_PROGRESS: + case AP_RESPONSE_BUSY: + break; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + case AP_RESPONSE_INVALID_ADDRESS: + return 0; + case AP_RESPONSE_OTHERWISE_CHANGED: + break; + default: + break; + } + if (i < AP_MAX_RESET - 1) { + udelay(5); + status = __ap_4096_commands_available(qid, &support); + } + } + return support; +} +EXPORT_SYMBOL(ap_4096_commands_available); + /** * ap_queue_enable_interruption(): Enable interruption on an AP. * @qid: The AP queue number diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 4785d07cd447..08b9738285b4 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -196,4 +196,6 @@ void ap_flush_queue(struct ap_device *ap_dev); int ap_module_init(void); void ap_module_exit(void); +int ap_4096_commands_available(ap_qid_t qid); + #endif /* _AP_BUS_H_ */ -- cgit v1.2.3 From 3e309a66f52e042881f76cbfb9b6c2aa70163e02 Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Wed, 5 Jan 2011 12:47:45 +0100 Subject: [S390] zcrypt: support for 4096 bit keys for cex3a Definitions for CEX3 card types are changed to support 4096 bit RSA keys. Also new structs for the accelerator mode are needed. Additionaly when checking the length of key parts, the case for bigger (4096 bit) keys is needed. Signed-off-by: Felix Beck Signed-off-by: Ralph Wuerthner Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_cex2a.c | 78 ++++++++++++++++++++++++++++++-------- drivers/s390/crypto/zcrypt_cex2a.h | 25 ++++++++++++ 2 files changed, 87 insertions(+), 16 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 9c409efa1ecf..def0901767de 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -41,7 +41,7 @@ #define CEX2A_MIN_MOD_SIZE 1 /* 8 bits */ #define CEX2A_MAX_MOD_SIZE 256 /* 2048 bits */ #define CEX3A_MIN_MOD_SIZE CEX2A_MIN_MOD_SIZE -#define CEX3A_MAX_MOD_SIZE CEX2A_MAX_MOD_SIZE +#define CEX3A_MAX_MOD_SIZE 512 /* 4096 bits */ #define CEX2A_SPEED_RATING 970 #define CEX3A_SPEED_RATING 900 /* Fixme: Needs finetuning */ @@ -49,8 +49,10 @@ #define CEX2A_MAX_MESSAGE_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */ #define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */ -#define CEX3A_MAX_MESSAGE_SIZE CEX2A_MAX_MESSAGE_SIZE -#define CEX3A_MAX_RESPONSE_SIZE CEX2A_MAX_RESPONSE_SIZE +#define CEX3A_MAX_RESPONSE_SIZE 0x210 /* 512 bit modulus + * (max outputdatalength) + + * type80_hdr*/ +#define CEX3A_MAX_MESSAGE_SIZE sizeof(struct type50_crb3_msg) #define CEX2A_CLEANUP_TIME (15*HZ) #define CEX3A_CLEANUP_TIME CEX2A_CLEANUP_TIME @@ -110,7 +112,7 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev, mod = meb1->modulus + sizeof(meb1->modulus) - mod_len; exp = meb1->exponent + sizeof(meb1->exponent) - mod_len; inp = meb1->message + sizeof(meb1->message) - mod_len; - } else { + } else if (mod_len <= 256) { struct type50_meb2_msg *meb2 = ap_msg->message; memset(meb2, 0, sizeof(*meb2)); ap_msg->length = sizeof(*meb2); @@ -120,6 +122,17 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev, mod = meb2->modulus + sizeof(meb2->modulus) - mod_len; exp = meb2->exponent + sizeof(meb2->exponent) - mod_len; inp = meb2->message + sizeof(meb2->message) - mod_len; + } else { + /* mod_len > 256 = 4096 bit RSA Key */ + struct type50_meb3_msg *meb3 = ap_msg->message; + memset(meb3, 0, sizeof(*meb3)); + ap_msg->length = sizeof(*meb3); + meb3->header.msg_type_code = TYPE50_TYPE_CODE; + meb3->header.msg_len = sizeof(*meb3); + meb3->keyblock_type = TYPE50_MEB3_FMT; + mod = meb3->modulus + sizeof(meb3->modulus) - mod_len; + exp = meb3->exponent + sizeof(meb3->exponent) - mod_len; + inp = meb3->message + sizeof(meb3->message) - mod_len; } if (copy_from_user(mod, mex->n_modulus, mod_len) || @@ -142,7 +155,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, struct ap_message *ap_msg, struct ica_rsa_modexpo_crt *crt) { - int mod_len, short_len, long_len, long_offset; + int mod_len, short_len, long_len, long_offset, limit; unsigned char *p, *q, *dp, *dq, *u, *inp; mod_len = crt->inputdatalength; @@ -152,14 +165,20 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, /* * CEX2A cannot handle p, dp, or U > 128 bytes. * If we have one of these, we need to do extra checking. + * For CEX3A the limit is 256 bytes. */ - if (long_len > 128) { + if (zdev->max_mod_size == CEX3A_MAX_MOD_SIZE) + limit = 256; + else + limit = 128; + + if (long_len > limit) { /* * zcrypt_rsa_crt already checked for the leading * zeroes of np_prime, bp_key and u_mult_inc. */ - long_offset = long_len - 128; - long_len = 128; + long_offset = long_len - limit; + long_len = limit; } else long_offset = 0; @@ -180,7 +199,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, dq = crb1->dq + sizeof(crb1->dq) - short_len; u = crb1->u + sizeof(crb1->u) - long_len; inp = crb1->message + sizeof(crb1->message) - mod_len; - } else { + } else if (long_len <= 128) { struct type50_crb2_msg *crb2 = ap_msg->message; memset(crb2, 0, sizeof(*crb2)); ap_msg->length = sizeof(*crb2); @@ -193,6 +212,20 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, dq = crb2->dq + sizeof(crb2->dq) - short_len; u = crb2->u + sizeof(crb2->u) - long_len; inp = crb2->message + sizeof(crb2->message) - mod_len; + } else { + /* long_len >= 256 */ + struct type50_crb3_msg *crb3 = ap_msg->message; + memset(crb3, 0, sizeof(*crb3)); + ap_msg->length = sizeof(*crb3); + crb3->header.msg_type_code = TYPE50_TYPE_CODE; + crb3->header.msg_len = sizeof(*crb3); + crb3->keyblock_type = TYPE50_CRB3_FMT; + p = crb3->p + sizeof(crb3->p) - long_len; + q = crb3->q + sizeof(crb3->q) - short_len; + dp = crb3->dp + sizeof(crb3->dp) - long_len; + dq = crb3->dq + sizeof(crb3->dq) - short_len; + u = crb3->u + sizeof(crb3->u) - long_len; + inp = crb3->message + sizeof(crb3->message) - mod_len; } if (copy_from_user(p, crt->np_prime + long_offset, long_len) || @@ -203,7 +236,6 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, copy_from_user(inp, crt->inputdata, mod_len)) return -EFAULT; - return 0; } @@ -230,7 +262,10 @@ static int convert_type80(struct zcrypt_device *zdev, zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } - BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE); + if (zdev->user_space_type == ZCRYPT_CEX2A) + BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE); + else + BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE); data = reply->message + t80h->len - outputdatalength; if (copy_to_user(outputdata, data, outputdatalength)) return -EFAULT; @@ -282,7 +317,10 @@ static void zcrypt_cex2a_receive(struct ap_device *ap_dev, } t80h = reply->message; if (t80h->type == TYPE80_RSP_CODE) { - length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len); + if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A) + length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len); + else + length = min(CEX3A_MAX_RESPONSE_SIZE, (int) t80h->len); memcpy(msg->message, reply->message, length); } else memcpy(msg->message, reply->message, sizeof error_reply); @@ -307,7 +345,10 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, int rc; ap_init_message(&ap_msg); - ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL); + if (zdev->user_space_type == ZCRYPT_CEX2A) + ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL); + else + ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + @@ -345,7 +386,10 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, int rc; ap_init_message(&ap_msg); - ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL); + if (zdev->user_space_type == ZCRYPT_CEX2A) + ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL); + else + ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + @@ -404,8 +448,10 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) return -ENOMEM; zdev->user_space_type = ZCRYPT_CEX3A; zdev->type_string = "CEX3A"; - zdev->min_mod_size = CEX3A_MIN_MOD_SIZE; - zdev->max_mod_size = CEX3A_MAX_MOD_SIZE; + zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; + zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; + if (ap_4096_commands_available(ap_dev->qid)) + zdev->max_mod_size = CEX3A_MAX_MOD_SIZE; zdev->short_crt = 1; zdev->speed_rating = CEX3A_SPEED_RATING; break; diff --git a/drivers/s390/crypto/zcrypt_cex2a.h b/drivers/s390/crypto/zcrypt_cex2a.h index 8f69d1dacab8..0350665810cf 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.h +++ b/drivers/s390/crypto/zcrypt_cex2a.h @@ -51,8 +51,10 @@ struct type50_hdr { #define TYPE50_MEB1_FMT 0x0001 #define TYPE50_MEB2_FMT 0x0002 +#define TYPE50_MEB3_FMT 0x0003 #define TYPE50_CRB1_FMT 0x0011 #define TYPE50_CRB2_FMT 0x0012 +#define TYPE50_CRB3_FMT 0x0013 /* Mod-Exp, with a small modulus */ struct type50_meb1_msg { @@ -74,6 +76,16 @@ struct type50_meb2_msg { unsigned char message[256]; } __attribute__((packed)); +/* Mod-Exp, with a larger modulus */ +struct type50_meb3_msg { + struct type50_hdr header; + unsigned short keyblock_type; /* 0x0003 */ + unsigned char reserved[6]; + unsigned char exponent[512]; + unsigned char modulus[512]; + unsigned char message[512]; +} __attribute__((packed)); + /* CRT, with a small modulus */ struct type50_crb1_msg { struct type50_hdr header; @@ -100,6 +112,19 @@ struct type50_crb2_msg { unsigned char message[256]; } __attribute__((packed)); +/* CRT, with a larger modulus */ +struct type50_crb3_msg { + struct type50_hdr header; + unsigned short keyblock_type; /* 0x0013 */ + unsigned char reserved[6]; + unsigned char p[256]; + unsigned char q[256]; + unsigned char dp[256]; + unsigned char dq[256]; + unsigned char u[256]; + unsigned char message[512]; +} __attribute__((packed)); + /** * The type 80 response family is associated with a CEX2A card. * -- cgit v1.2.3 From 2ade1fab026b4a103f0105ec4b47654fc2f729c7 Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Wed, 5 Jan 2011 12:47:46 +0100 Subject: [S390] zcrypt: support for 4096 bit keys for cex3c Definitions for CEX3 card types are changed to support 4096 bit RSA keys in the coprocessor. Signed-off-by: Felix Beck Signed-off-by: Ralph Wuerthner Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_pcixcc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 510fab4577d4..fc8eb9dce841 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -45,12 +45,12 @@ #define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */ #define PCIXCC_MAX_MOD_SIZE 256 /* 2048 bits */ #define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE -#define CEX3C_MAX_MOD_SIZE PCIXCC_MAX_MOD_SIZE +#define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */ #define PCIXCC_MCL2_SPEED_RATING 7870 #define PCIXCC_MCL3_SPEED_RATING 7870 #define CEX2C_SPEED_RATING 7000 -#define CEX3C_SPEED_RATING 6500 /* FIXME: needs finetuning */ +#define CEX3C_SPEED_RATING 6500 #define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */ #define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */ -- cgit v1.2.3 From c2567f8ffa2704f6f2f81013e9a590deca5a865f Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Wed, 5 Jan 2011 12:47:47 +0100 Subject: [S390] zcrypt: cope with cca restriction of cex3 The cca on the crypto adapter has a restriction in the size of the exponent if a key with a modulus bigger than 2048 bit is used. Thus in that case we have to avoid that the crypto device driver thinks the adapter is defect and sets it offline. Therfore a new member for the zcrypt_device struct called max_exp_bit_length is introduced. This will be set the first time the cca returns the error code function not implemented. If this is done with an adapter twice it will return -EINVAL. Signed-off-by: Felix Beck Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_api.h | 1 + drivers/s390/crypto/zcrypt_cex2a.c | 6 +++++- drivers/s390/crypto/zcrypt_pcica.c | 1 + drivers/s390/crypto/zcrypt_pcicc.c | 1 + drivers/s390/crypto/zcrypt_pcixcc.c | 13 +++++++++++++ 5 files changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 8e7ffbf2466c..88ebd114735b 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -109,6 +109,7 @@ struct zcrypt_device { int request_count; /* # current requests. */ struct ap_message reply; /* Per-device reply structure. */ + int max_exp_bit_length; }; struct zcrypt_device *zcrypt_device_alloc(size_t); diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index def0901767de..2176d00b395e 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -441,6 +441,7 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; zdev->short_crt = 1; zdev->speed_rating = CEX2A_SPEED_RATING; + zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; break; case AP_DEVICE_TYPE_CEX3A: zdev = zcrypt_device_alloc(CEX3A_MAX_RESPONSE_SIZE); @@ -450,8 +451,11 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) zdev->type_string = "CEX3A"; zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; - if (ap_4096_commands_available(ap_dev->qid)) + zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; + if (ap_4096_commands_available(ap_dev->qid)) { zdev->max_mod_size = CEX3A_MAX_MOD_SIZE; + zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; + } zdev->short_crt = 1; zdev->speed_rating = CEX3A_SPEED_RATING; break; diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c index 09e934b295a0..1afb69c75fea 100644 --- a/drivers/s390/crypto/zcrypt_pcica.c +++ b/drivers/s390/crypto/zcrypt_pcica.c @@ -373,6 +373,7 @@ static int zcrypt_pcica_probe(struct ap_device *ap_dev) zdev->min_mod_size = PCICA_MIN_MOD_SIZE; zdev->max_mod_size = PCICA_MAX_MOD_SIZE; zdev->speed_rating = PCICA_SPEED_RATING; + zdev->max_exp_bit_length = PCICA_MAX_MOD_SIZE; ap_dev->reply = &zdev->reply; ap_dev->private = zdev; rc = zcrypt_device_register(zdev); diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c index 9dec5c77cff4..aa4c050a5694 100644 --- a/drivers/s390/crypto/zcrypt_pcicc.c +++ b/drivers/s390/crypto/zcrypt_pcicc.c @@ -579,6 +579,7 @@ static int zcrypt_pcicc_probe(struct ap_device *ap_dev) zdev->min_mod_size = PCICC_MIN_MOD_SIZE; zdev->max_mod_size = PCICC_MAX_MOD_SIZE; zdev->speed_rating = PCICC_SPEED_RATING; + zdev->max_exp_bit_length = PCICC_MAX_MOD_SIZE; ap_dev->reply = &zdev->reply; ap_dev->private = zdev; rc = zcrypt_device_register(zdev); diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index fc8eb9dce841..4f85eb725f4f 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -567,6 +567,15 @@ static int convert_response_ica(struct zcrypt_device *zdev, case TYPE88_RSP_CODE: return convert_error(zdev, reply); case TYPE86_RSP_CODE: + if (msg->cprbx.ccp_rtcode && + (msg->cprbx.ccp_rscode == 0x14f) && + (outputdatalength > 256)) { + if (zdev->max_exp_bit_length <= 17) { + zdev->max_exp_bit_length = 17; + return -EAGAIN; + } else + return -EINVAL; + } if (msg->hdr.reply_code) return convert_error(zdev, reply); if (msg->cprbx.cprb_ver_id == 0x02) @@ -1052,11 +1061,13 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING; zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; + zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; } else { zdev->type_string = "PCIXCC_MCL3"; zdev->speed_rating = PCIXCC_MCL3_SPEED_RATING; zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; + zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; } break; case AP_DEVICE_TYPE_CEX2C: @@ -1065,6 +1076,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) zdev->speed_rating = CEX2C_SPEED_RATING; zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; + zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; break; case AP_DEVICE_TYPE_CEX3C: zdev->user_space_type = ZCRYPT_CEX3C; @@ -1072,6 +1084,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) zdev->speed_rating = CEX3C_SPEED_RATING; zdev->min_mod_size = CEX3C_MIN_MOD_SIZE; zdev->max_mod_size = CEX3C_MAX_MOD_SIZE; + zdev->max_exp_bit_length = CEX3C_MAX_MOD_SIZE; break; default: goto out_free; -- cgit v1.2.3 From 078f8ecaa30718694d1e13d9f415b7ce75b3c968 Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Wed, 5 Jan 2011 12:47:48 +0100 Subject: [S390] Handling of 4096 bit RSA keys in CRT format. Also process 4096 bit RSA keys in CRT format. Handle them like the smaller keys and take care of the zero padding. Signed-off-by: Felix Beck Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_api.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 7fca9c10ffcf..8e65447f76b7 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -396,8 +396,15 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) if (copied == 0) { unsigned int len; spin_unlock_bh(&zcrypt_device_lock); - /* len is max 256 / 2 - 120 = 8 */ - len = crt->inputdatalength / 2 - 120; + /* len is max 256 / 2 - 120 = 8 + * For bigger device just assume len of leading + * 0s is 8 as stated in the requirements for + * ica_rsa_modexpo_crt struct in zcrypt.h. + */ + if (crt->inputdatalength <= 256) + len = crt->inputdatalength / 2 - 120; + else + len = 8; if (len > sizeof(z1)) return -EFAULT; z1 = z2 = z3 = 0; @@ -405,6 +412,7 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) copy_from_user(&z2, crt->bp_key, len) || copy_from_user(&z3, crt->u_mult_inv, len)) return -EFAULT; + z1 = z2 = z3 = 0; copied = 1; /* * We have to restart device lookup - -- cgit v1.2.3 From 4f325184f2d4c1f2258873b2a333005dc4dfcbc0 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 5 Jan 2011 12:47:49 +0100 Subject: [S390] qdio: prevent race for shared indicators If the shared indicator is used the following race leads to an inbound stall: Device CPU0 CPU1 ======================================================== non-shared DSCI =>1 ALSI => 1 Thin INT ALSI => 0 non-shared DSCI tasklets scheduled shared DSCI => 1 ALSI => 1 shared DSCI => 0 ALSI ? -> set Thin INT ALSI => 0 ALSI was set, shared DSCI => 1 After that no more interrupts occur because the DSCI is still set. Fix that race by only resetting the shared DSCI if it was actually set so the tasklets for all shared devices are scheduled and will run after the interrupt. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio.h | 4 +-- drivers/s390/cio/qdio_main.c | 4 +-- drivers/s390/cio/qdio_thinint.c | 54 +++++++---------------------------------- 3 files changed, 13 insertions(+), 49 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 0f4ef8769a3d..9b6ea3ca3ece 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -423,9 +423,9 @@ struct indicator_t { extern struct indicator_t *q_indicators; -static inline int shared_ind(struct qdio_irq *irq_ptr) +static inline int shared_ind(u32 *dsci) { - return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; + return dsci == &q_indicators[TIQDIO_SHARED_IND].ind; } /* prototypes for thin interrupt */ diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 194ea8c182b2..6621de94f3ad 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1552,7 +1552,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr) WARN_ON(queue_irqs_enabled(q)); - if (!shared_ind(q->irq_ptr)) + if (!shared_ind(q->irq_ptr->dsci)) xchg(q->irq_ptr->dsci, 0); qdio_stop_polling(q); @@ -1562,7 +1562,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr) * We need to check again to not lose initiative after * resetting the ACK state. */ - if (!shared_ind(q->irq_ptr) && *q->irq_ptr->dsci) + if (!shared_ind(q->irq_ptr->dsci) && *q->irq_ptr->dsci) goto rescan; if (!qdio_inbound_q_done(q)) goto rescan; diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 64b59a58a1cd..5c4e741d8221 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -36,22 +36,8 @@ static u8 *tiqdio_alsi; struct indicator_t *q_indicators; -static int css_qdio_omit_svs; - static u64 last_ai_time; -static inline unsigned long do_clear_global_summary(void) -{ - register unsigned long __fn asm("1") = 3; - register unsigned long __tmp asm("2"); - register unsigned long __time asm("3"); - - asm volatile( - " .insn rre,0xb2650000,2,0" - : "+d" (__fn), "=d" (__tmp), "=d" (__time)); - return __time; -} - /* returns addr for the device state change indicator */ static u32 *get_indicator(void) { @@ -84,10 +70,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) struct qdio_q *q; int i; - /* No TDD facility? If we must use SIGA-s we can also omit SVS. */ - if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync) - css_qdio_omit_svs = 1; - mutex_lock(&tiq_list_lock); for_each_input_queue(irq_ptr, q, i) list_add_rcu(&q->entry, &tiq_list); @@ -113,9 +95,9 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) } } -static inline int shared_ind_used(void) +static inline u32 shared_ind_set(void) { - return atomic_read(&q_indicators[TIQDIO_SHARED_IND].count); + return q_indicators[TIQDIO_SHARED_IND].ind; } /** @@ -125,22 +107,12 @@ static inline int shared_ind_used(void) */ static void tiqdio_thinint_handler(void *alsi, void *data) { + u32 si_used = shared_ind_set(); struct qdio_q *q; last_ai_time = S390_lowcore.int_clock; kstat_cpu(smp_processor_id()).irqs[IOINT_QAI]++; - /* - * SVS only when needed: issue SVS to benefit from iqdio interrupt - * avoidance (SVS clears adapter interrupt suppression overwrite). - */ - if (!css_qdio_omit_svs) - do_clear_global_summary(); - - /* reset local summary indicator */ - if (shared_ind_used()) - xchg(tiqdio_alsi, 0); - /* protect tiq_list entries, only changed in activate or shutdown */ rcu_read_lock(); @@ -148,7 +120,10 @@ static void tiqdio_thinint_handler(void *alsi, void *data) list_for_each_entry_rcu(q, &tiq_list, entry) { /* only process queues from changed sets */ - if (!*q->irq_ptr->dsci) + if (unlikely(shared_ind(q->irq_ptr->dsci))) { + if (!si_used) + continue; + } else if (!*q->irq_ptr->dsci) continue; if (q->u.in.queue_start_poll) { @@ -164,7 +139,7 @@ static void tiqdio_thinint_handler(void *alsi, void *data) q->irq_ptr->int_parm); } else { /* only clear it if the indicator is non-shared */ - if (!shared_ind(q->irq_ptr)) + if (!shared_ind(q->irq_ptr->dsci)) xchg(q->irq_ptr->dsci, 0); /* * Call inbound processing but not directly @@ -180,13 +155,8 @@ static void tiqdio_thinint_handler(void *alsi, void *data) * If the shared indicator was used clear it now after all queues * were processed. */ - if (shared_ind_used()) { + if (si_used && shared_ind_set()) xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0); - - /* prevent racing */ - if (*tiqdio_alsi) - xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1 << 7); - } } static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) @@ -271,12 +241,6 @@ int qdio_establish_thinint(struct qdio_irq *irq_ptr) { if (!is_thinint_irq(irq_ptr)) return 0; - - /* Check for aif time delay disablement. If installed, - * omit SVS even under LPAR - */ - if (css_general_characteristics.aif_tdd) - css_qdio_omit_svs = 1; return set_subchannel_ind(irq_ptr, 0); } -- cgit v1.2.3 From 3d6c76ff32bb9b2ebf6e859855d315eb42e3df50 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 5 Jan 2011 12:47:50 +0100 Subject: [S390] qdio: outbound tasklet scan threshold Introduce a scan treshold for the qdio outbound queues. By setting the threshold the driver can tell qdio after how much used SBALs qdio should schedule the outbound tasklet that scans the queue for finished SBALs. The threshold is specific by the drivers because a Hipersockets device is much faster in utilizing outbound buffers than a ZFCP or OSA device. The default values after how many used SBALs the tasklet should run are: OSA: > 31 SBALs Hipersockets: > 7 SBALs zfcp: > 55 SBALs Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/qdio.h | 1 + drivers/s390/cio/qdio.h | 2 ++ drivers/s390/cio/qdio_main.c | 8 +++++++- drivers/s390/cio/qdio_setup.c | 1 + drivers/s390/net/qeth_core_main.c | 2 ++ drivers/s390/scsi/zfcp_qdio.c | 2 ++ 6 files changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 46e96bc1f5a1..350e7ee5952d 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -361,6 +361,7 @@ struct qdio_initialize { qdio_handler_t *input_handler; qdio_handler_t *output_handler; void (*queue_start_poll) (struct ccw_device *, int, unsigned long); + int scan_threshold; unsigned long int_parm; void **input_sbal_addr_array; void **output_sbal_addr_array; diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 9b6ea3ca3ece..a77aa9109cfd 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -249,6 +249,8 @@ struct qdio_output_q { int use_enh_siga; /* timer to check for more outbound work */ struct timer_list timer; + /* used SBALs before tasklet schedule */ + int scan_threshold; }; /* diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 6621de94f3ad..4c0109900c74 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1492,7 +1492,13 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags, qperf_inc(q, fast_requeue); out: - tasklet_schedule(&q->tasklet); + /* in case of SIGA errors we must process the error immediately */ + if (used >= q->u.out.scan_threshold || rc) + tasklet_schedule(&q->tasklet); + else + /* free the SBALs in case of no further traffic */ + if (!timer_pending(&q->u.out.timer)) + mod_timer(&q->u.out.timer, jiffies + HZ); return rc; } diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index a13cf7ec64b2..635f35dc8466 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -178,6 +178,7 @@ static void setup_queues(struct qdio_irq *irq_ptr, setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i); q->is_input_q = 0; + q->u.out.scan_threshold = qdio_init->scan_threshold; setup_storage_lists(q, irq_ptr, output_sbal_array, i); output_sbal_array += QDIO_MAX_BUFFERS_PER_Q; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index e6b2df0e73f5..f65320babf71 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3831,6 +3831,8 @@ static int qeth_qdio_establish(struct qeth_card *card) init_data.int_parm = (unsigned long) card; init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; + init_data.scan_threshold = + (card->info.type == QETH_CARD_TYPE_IQD) ? 8 : 32; if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED, QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) { diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index a0554beb4179..5ae40ef586a8 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -292,6 +292,8 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, id->int_parm = (unsigned long) qdio; id->input_sbal_addr_array = (void **) (qdio->res_q); id->output_sbal_addr_array = (void **) (qdio->req_q); + id->scan_threshold = + QDIO_MAX_BUFFERS_PER_Q - ZFCP_QDIO_MAX_SBALS_PER_REQ * 2; } /** -- cgit v1.2.3 From 0195843bfda90a215f3b72c9aac2fd0bc9244b67 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 5 Jan 2011 12:47:51 +0100 Subject: [S390] qdio: outbound queue full counter Add a counter for outbound queue full events to the qdio statistics. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio.h | 1 + drivers/s390/cio/qdio_debug.c | 1 + drivers/s390/cio/qdio_main.c | 3 +++ 3 files changed, 5 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index a77aa9109cfd..40ca0b9241e5 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -202,6 +202,7 @@ struct qdio_dev_perf_stat { unsigned int inbound_queue_full; unsigned int outbound_call; unsigned int outbound_handler; + unsigned int outbound_queue_full; unsigned int fast_requeue; unsigned int target_full; unsigned int eqbs; diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 28868e7471a5..f8b03a636e49 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -151,6 +151,7 @@ static char *qperf_names[] = { "Inbound queue full", "Outbound calls", "Outbound handler", + "Outbound queue full", "Outbound fast_requeue", "Outbound target_full", "QEBSM eqbs", diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 4c0109900c74..af86875bede4 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1447,6 +1447,9 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags, used = atomic_add_return(count, &q->nr_buf_used); BUG_ON(used > QDIO_MAX_BUFFERS_PER_Q); + if (used == QDIO_MAX_BUFFERS_PER_Q) + qperf_inc(q, outbound_queue_full); + if (callflags & QDIO_FLAG_PCI_OUT) { q->u.out.pci_out_enabled = 1; qperf_inc(q, pci_request_int); -- cgit v1.2.3 From 958c0ba403cb6a693b54be2389f9ef53377fa259 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 5 Jan 2011 12:47:52 +0100 Subject: [S390] qdio: use proper QEBSM operand for SIGA-R and SIGA-S If QIOASSIST is enabled for a qdio device the SIGA instruction requires a modified function code. This function code modifier was missing for SIGA-R and SIGA-S which can lead to a kernel panic caused by an operand exception. Cc: stable@kernel.org Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio.h | 6 ++++++ drivers/s390/cio/qdio_main.c | 43 ++++++++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 15 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 40ca0b9241e5..0a42da4beafa 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -91,6 +91,12 @@ enum qdio_irq_states { #define AC1_SC_QEBSM_AVAILABLE 0x02 /* available for subchannel */ #define AC1_SC_QEBSM_ENABLED 0x01 /* enabled for subchannel */ +/* SIGA flags */ +#define QDIO_SIGA_WRITE 0x00 +#define QDIO_SIGA_READ 0x01 +#define QDIO_SIGA_SYNC 0x02 +#define QDIO_SIGA_QEBSM_FLAG 0x80 + #ifdef CONFIG_64BIT static inline int do_sqbs(u64 token, unsigned char state, int queue, int *start, int *count) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index af86875bede4..99823477d57e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -30,11 +30,12 @@ MODULE_AUTHOR("Utz Bacher ,"\ MODULE_DESCRIPTION("QDIO base support"); MODULE_LICENSE("GPL"); -static inline int do_siga_sync(struct subchannel_id schid, - unsigned int out_mask, unsigned int in_mask) +static inline int do_siga_sync(unsigned long schid, + unsigned int out_mask, unsigned int in_mask, + unsigned int fc) { - register unsigned long __fc asm ("0") = 2; - register struct subchannel_id __schid asm ("1") = schid; + register unsigned long __fc asm ("0") = fc; + register unsigned long __schid asm ("1") = schid; register unsigned long out asm ("2") = out_mask; register unsigned long in asm ("3") = in_mask; int cc; @@ -48,10 +49,11 @@ static inline int do_siga_sync(struct subchannel_id schid, return cc; } -static inline int do_siga_input(struct subchannel_id schid, unsigned int mask) +static inline int do_siga_input(unsigned long schid, unsigned int mask, + unsigned int fc) { - register unsigned long __fc asm ("0") = 1; - register struct subchannel_id __schid asm ("1") = schid; + register unsigned long __fc asm ("0") = fc; + register unsigned long __schid asm ("1") = schid; register unsigned long __mask asm ("2") = mask; int cc; @@ -280,6 +282,8 @@ void qdio_init_buf_states(struct qdio_irq *irq_ptr) static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, unsigned int input) { + unsigned long schid = *((u32 *) &q->irq_ptr->schid); + unsigned int fc = QDIO_SIGA_SYNC; int cc; if (!need_siga_sync(q)) @@ -288,7 +292,12 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr); qperf_inc(q, siga_sync); - cc = do_siga_sync(q->irq_ptr->schid, output, input); + if (is_qebsm(q)) { + schid = q->irq_ptr->sch_token; + fc |= QDIO_SIGA_QEBSM_FLAG; + } + + cc = do_siga_sync(schid, output, input, fc); if (cc) DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); return cc; @@ -314,8 +323,8 @@ static inline int qdio_siga_sync_all(struct qdio_q *q) static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) { - unsigned long schid; - unsigned int fc = 0; + unsigned long schid = *((u32 *) &q->irq_ptr->schid); + unsigned int fc = QDIO_SIGA_WRITE; u64 start_time = 0; int cc; @@ -324,11 +333,8 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) if (is_qebsm(q)) { schid = q->irq_ptr->sch_token; - fc |= 0x80; + fc |= QDIO_SIGA_QEBSM_FLAG; } - else - schid = *((u32 *)&q->irq_ptr->schid); - again: cc = do_siga_output(schid, q->mask, busy_bit, fc); @@ -348,12 +354,19 @@ again: static inline int qdio_siga_input(struct qdio_q *q) { + unsigned long schid = *((u32 *) &q->irq_ptr->schid); + unsigned int fc = QDIO_SIGA_READ; int cc; DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr); qperf_inc(q, siga_read); - cc = do_siga_input(q->irq_ptr->schid, q->mask); + if (is_qebsm(q)) { + schid = q->irq_ptr->sch_token; + fc |= QDIO_SIGA_QEBSM_FLAG; + } + + cc = do_siga_input(schid, q->mask, fc); if (cc) DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); return cc; -- cgit v1.2.3 From 110da31709023de61735f2d8a3e52c20c23bb570 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 5 Jan 2011 12:47:53 +0100 Subject: [S390] qdio: remove enhanced SIGA HiperSocket devices only use one SBAL per qdio call without the enhanced SIGA feature. Since that feature is currently not used remove it from the qdio code so the compiler can generate better code for the HiperSocket outbound path. While at it mark the SIGA error conditions as unlikely. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio.h | 2 -- drivers/s390/cio/qdio_main.c | 57 ++++++++++++-------------------------------- 2 files changed, 15 insertions(+), 44 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 0a42da4beafa..1b40a92fec14 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -252,8 +252,6 @@ struct qdio_input_q { struct qdio_output_q { /* PCIs are enabled for the queue */ int pci_out_enabled; - /* IQDIO: output multiple buffers (enhanced SIGA) */ - int use_enh_siga; /* timer to check for more outbound work */ struct timer_list timer; /* used SBALs before tasklet schedule */ diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 99823477d57e..8a722f208325 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -298,7 +298,7 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, } cc = do_siga_sync(schid, output, input, fc); - if (cc) + if (unlikely(cc)) DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); return cc; } @@ -328,9 +328,6 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) u64 start_time = 0; int cc; - if (q->u.out.use_enh_siga) - fc = 3; - if (is_qebsm(q)) { schid = q->irq_ptr->sch_token; fc |= QDIO_SIGA_QEBSM_FLAG; @@ -339,7 +336,7 @@ again: cc = do_siga_output(schid, q->mask, busy_bit, fc); /* hipersocket busy condition */ - if (*busy_bit) { + if (unlikely(*busy_bit)) { WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); if (!start_time) { @@ -367,7 +364,7 @@ static inline int qdio_siga_input(struct qdio_q *q) } cc = do_siga_input(schid, q->mask, fc); - if (cc) + if (unlikely(cc)) DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); return cc; } @@ -1288,7 +1285,6 @@ int qdio_establish(struct qdio_initialize *init_data) } qdio_setup_ssqd_info(irq_ptr); - DBF_EVENT("qDmmwc:%2x", irq_ptr->ssqd_desc.mmwc); DBF_EVENT("qib ac:%4x", irq_ptr->qib.ac); /* qebsm is now setup if available, initialize buffer states */ @@ -1466,48 +1462,25 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags, if (callflags & QDIO_FLAG_PCI_OUT) { q->u.out.pci_out_enabled = 1; qperf_inc(q, pci_request_int); - } - else + } else q->u.out.pci_out_enabled = 0; if (queue_type(q) == QDIO_IQDIO_QFMT) { - if (multicast_outbound(q)) + /* One SIGA-W per buffer required for unicast HiperSockets. */ + WARN_ON_ONCE(count > 1 && !multicast_outbound(q)); + + rc = qdio_kick_outbound_q(q); + } else if (unlikely(need_siga_sync(q))) { + rc = qdio_siga_sync_q(q); + } else { + /* try to fast requeue buffers */ + get_buf_state(q, prev_buf(bufnr), &state, 0); + if (state != SLSB_CU_OUTPUT_PRIMED) rc = qdio_kick_outbound_q(q); else - if ((q->irq_ptr->ssqd_desc.mmwc > 1) && - (count > 1) && - (count <= q->irq_ptr->ssqd_desc.mmwc)) { - /* exploit enhanced SIGA */ - q->u.out.use_enh_siga = 1; - rc = qdio_kick_outbound_q(q); - } else { - /* - * One siga-w per buffer required for unicast - * HiperSockets. - */ - q->u.out.use_enh_siga = 0; - while (count--) { - rc = qdio_kick_outbound_q(q); - if (rc) - goto out; - } - } - goto out; + qperf_inc(q, fast_requeue); } - if (need_siga_sync(q)) { - qdio_siga_sync_q(q); - goto out; - } - - /* try to fast requeue buffers */ - get_buf_state(q, prev_buf(bufnr), &state, 0); - if (state != SLSB_CU_OUTPUT_PRIMED) - rc = qdio_kick_outbound_q(q); - else - qperf_inc(q, fast_requeue); - -out: /* in case of SIGA errors we must process the error immediately */ if (used >= q->u.out.scan_threshold || rc) tasklet_schedule(&q->tasklet); -- cgit v1.2.3 From 90adac58d1a4daf3560739ff5b76497d5ece16c4 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 5 Jan 2011 12:47:54 +0100 Subject: [S390] qdio: cleanup SIGA sync Simplify the SIGA sync code and add unlikely annotations. In polling mode SBALs may be accessed without interrupt, so call SIGA sync before every scan. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio.h | 16 +++++------ drivers/s390/cio/qdio_main.c | 64 ++++++++++++++++++++----------------------- drivers/s390/cio/qdio_setup.c | 19 +++++-------- 3 files changed, 44 insertions(+), 55 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 1b40a92fec14..7bc643f3f5ab 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -148,10 +148,9 @@ struct siga_flag { u8 input:1; u8 output:1; u8 sync:1; - u8 no_sync_ti:1; - u8 no_sync_out_ti:1; - u8 no_sync_out_pci:1; - u8:2; + u8 sync_after_ai:1; + u8 sync_out_after_pci:1; + u8:3; } __attribute__ ((packed)); struct chsc_ssqd_area { @@ -390,12 +389,13 @@ static inline int multicast_outbound(struct qdio_q *q) (q->irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) #define is_qebsm(q) (q->irq_ptr->sch_token != 0) -#define need_siga_sync_thinint(q) (!q->irq_ptr->siga_flag.no_sync_ti) -#define need_siga_sync_out_thinint(q) (!q->irq_ptr->siga_flag.no_sync_out_ti) #define need_siga_in(q) (q->irq_ptr->siga_flag.input) #define need_siga_out(q) (q->irq_ptr->siga_flag.output) -#define need_siga_sync(q) (q->irq_ptr->siga_flag.sync) -#define siga_syncs_out_pci(q) (q->irq_ptr->siga_flag.no_sync_out_pci) +#define need_siga_sync(q) (unlikely(q->irq_ptr->siga_flag.sync)) +#define need_siga_sync_after_ai(q) \ + (unlikely(q->irq_ptr->siga_flag.sync_after_ai)) +#define need_siga_sync_out_after_pci(q) \ + (unlikely(q->irq_ptr->siga_flag.sync_out_after_pci)) #define for_each_input_queue(irq_ptr, q, i) \ for (i = 0, q = irq_ptr->input_qs[0]; \ diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 8a722f208325..e9fff2b9bce2 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -286,9 +286,6 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, unsigned int fc = QDIO_SIGA_SYNC; int cc; - if (!need_siga_sync(q)) - return 0; - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr); qperf_inc(q, siga_sync); @@ -311,16 +308,6 @@ static inline int qdio_siga_sync_q(struct qdio_q *q) return qdio_siga_sync(q, q->mask, 0); } -static inline int qdio_siga_sync_out(struct qdio_q *q) -{ - return qdio_siga_sync(q, ~0U, 0); -} - -static inline int qdio_siga_sync_all(struct qdio_q *q) -{ - return qdio_siga_sync(q, ~0U, ~0U); -} - static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) { unsigned long schid = *((u32 *) &q->irq_ptr->schid); @@ -369,21 +356,23 @@ static inline int qdio_siga_input(struct qdio_q *q) return cc; } -static inline void qdio_sync_after_thinint(struct qdio_q *q) +#define qdio_siga_sync_out(q) qdio_siga_sync(q, ~0U, 0) +#define qdio_siga_sync_all(q) qdio_siga_sync(q, ~0U, ~0U) + +static inline void qdio_sync_queues(struct qdio_q *q) { - if (pci_out_supported(q)) { - if (need_siga_sync_thinint(q)) - qdio_siga_sync_all(q); - else if (need_siga_sync_out_thinint(q)) - qdio_siga_sync_out(q); - } else + /* PCI capable outbound queues will also be scanned so sync them too */ + if (pci_out_supported(q)) + qdio_siga_sync_all(q); + else qdio_siga_sync_q(q); } int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state) { - qdio_siga_sync_q(q); + if (need_siga_sync(q)) + qdio_siga_sync_q(q); return get_buf_states(q, bufnr, state, 1, 0); } @@ -560,7 +549,8 @@ static inline int qdio_inbound_q_done(struct qdio_q *q) if (!atomic_read(&q->nr_buf_used)) return 1; - qdio_siga_sync_q(q); + if (need_siga_sync(q)) + qdio_siga_sync_q(q); get_buf_state(q, q->first_to_check, &state, 0); if (state == SLSB_P_INPUT_PRIMED || state == SLSB_P_INPUT_ERROR) @@ -655,9 +645,12 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) int count, stop; unsigned char state; - if (((queue_type(q) != QDIO_IQDIO_QFMT) && !pci_out_supported(q)) || - (queue_type(q) == QDIO_IQDIO_QFMT && multicast_outbound(q))) - qdio_siga_sync_q(q); + if (need_siga_sync(q)) + if (((queue_type(q) != QDIO_IQDIO_QFMT) && + !pci_out_supported(q)) || + (queue_type(q) == QDIO_IQDIO_QFMT && + multicast_outbound(q))) + qdio_siga_sync_q(q); /* * Don't check 128 buffers, as otherwise qdio_inbound_q_moved @@ -829,7 +822,8 @@ static inline void qdio_check_outbound_after_thinint(struct qdio_q *q) static void __tiqdio_inbound_processing(struct qdio_q *q) { qperf_inc(q, tasklet_inbound); - qdio_sync_after_thinint(q); + if (need_siga_sync(q) && need_siga_sync_after_ai(q)) + qdio_sync_queues(q); /* * The interrupt could be caused by a PCI request. Check the @@ -909,16 +903,14 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr) tasklet_schedule(&q->tasklet); } - if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED)) + if (!pci_out_supported(q)) return; for_each_output_queue(irq_ptr, q, i) { if (qdio_outbound_q_done(q)) continue; - - if (!siga_syncs_out_pci(q)) + if (need_siga_sync(q) && need_siga_sync_out_after_pci(q)) qdio_siga_sync_q(q); - tasklet_schedule(&q->tasklet); } } @@ -1470,7 +1462,7 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags, WARN_ON_ONCE(count > 1 && !multicast_outbound(q)); rc = qdio_kick_outbound_q(q); - } else if (unlikely(need_siga_sync(q))) { + } else if (need_siga_sync(q)) { rc = qdio_siga_sync_q(q); } else { /* try to fast requeue buffers */ @@ -1597,12 +1589,14 @@ int qdio_get_next_buffers(struct ccw_device *cdev, int nr, int *bufnr, q = irq_ptr->input_qs[nr]; WARN_ON(queue_irqs_enabled(q)); - qdio_sync_after_thinint(q); - /* - * The interrupt could be caused by a PCI request. Check the - * PCI capable outbound queues. + * Cannot rely on automatic sync after interrupt since queues may + * also be examined without interrupt. */ + if (need_siga_sync(q)) + qdio_sync_queues(q); + + /* check the PCI capable outbound queues. */ qdio_check_outbound_after_thinint(q); if (!qdio_inbound_q_moved(q)) diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 635f35dc8466..89107d0938c4 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -197,14 +197,10 @@ static void process_ac_flags(struct qdio_irq *irq_ptr, unsigned char qdioac) irq_ptr->siga_flag.output = 1; if (qdioac & AC1_SIGA_SYNC_NEEDED) irq_ptr->siga_flag.sync = 1; - if (qdioac & AC1_AUTOMATIC_SYNC_ON_THININT) - irq_ptr->siga_flag.no_sync_ti = 1; - if (qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI) - irq_ptr->siga_flag.no_sync_out_pci = 1; - - if (irq_ptr->siga_flag.no_sync_out_pci && - irq_ptr->siga_flag.no_sync_ti) - irq_ptr->siga_flag.no_sync_out_ti = 1; + if (!(qdioac & AC1_AUTOMATIC_SYNC_ON_THININT)) + irq_ptr->siga_flag.sync_after_ai = 1; + if (!(qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI)) + irq_ptr->siga_flag.sync_out_after_pci = 1; } static void check_and_setup_qebsm(struct qdio_irq *irq_ptr, @@ -452,7 +448,7 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, char s[80]; snprintf(s, 80, "qdio: %s %s on SC %x using " - "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s%s\n", + "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s\n", dev_name(&cdev->dev), (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" : ((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"), @@ -464,9 +460,8 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, (irq_ptr->siga_flag.input) ? "R" : " ", (irq_ptr->siga_flag.output) ? "W" : " ", (irq_ptr->siga_flag.sync) ? "S" : " ", - (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ", - (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ", - (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " "); + (irq_ptr->siga_flag.sync_after_ai) ? "A" : " ", + (irq_ptr->siga_flag.sync_out_after_pci) ? "P" : " "); printk(KERN_INFO "%s", s); } -- cgit v1.2.3 From ce322ccd53f2505cf8b0ed204631d6ac054ac66a Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 5 Jan 2011 12:47:56 +0100 Subject: [S390] cio: obtain mdc value per channel path Add support to accumulate the number of 64K-bytes blocks all paths to a device at least support for a transport command. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/ccwdev.h | 2 ++ drivers/s390/cio/chsc.c | 19 +++++++++++++++++++ drivers/s390/cio/chsc.h | 18 ++++++++++++++++++ drivers/s390/cio/device_ops.c | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index e8501115eca8..ff6f62e0ec3e 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h @@ -204,6 +204,8 @@ int ccw_device_tm_start_timeout(struct ccw_device *, struct tcw *, unsigned long, u8, int); int ccw_device_tm_intrg(struct ccw_device *cdev); +int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask); + extern int ccw_device_set_online(struct ccw_device *cdev); extern int ccw_device_set_offline(struct ccw_device *cdev); diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 1aaddea673e0..0689fcf23a11 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -695,6 +695,25 @@ out: return ret; } +int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, + struct channel_path_desc_fmt1 *desc) +{ + struct chsc_response_struct *chsc_resp; + struct chsc_scpd *scpd_area; + int ret; + + spin_lock_irq(&chsc_page_lock); + scpd_area = chsc_page; + ret = chsc_determine_channel_path_desc(chpid, 0, 0, 1, 0, scpd_area); + if (ret) + goto out; + chsc_resp = (void *)&scpd_area->response; + memcpy(desc, &chsc_resp->data, sizeof(*desc)); +out: + spin_unlock_irq(&chsc_page_lock); + return ret; +} + static void chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, struct cmg_chars *chars) diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 6693f5e3176f..3f15b2aaeaea 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -35,6 +35,22 @@ struct channel_path_desc { u8 chpp; } __attribute__ ((packed)); +struct channel_path_desc_fmt1 { + u8 flags; + u8 lsn; + u8 desc; + u8 chpid; + u32:24; + u8 chpp; + u32 unused[3]; + u16 mdc; + u16:13; + u8 r:1; + u8 s:1; + u8 f:1; + u32 zeros[2]; +} __attribute__ ((packed)); + struct channel_path; struct css_chsc_char { @@ -92,6 +108,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, int c, int m, void *page); int chsc_determine_base_channel_path_desc(struct chp_id chpid, struct channel_path_desc *desc); +int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, + struct channel_path_desc_fmt1 *desc); void chsc_chp_online(struct chp_id chpid); void chsc_chp_offline(struct chp_id chpid); int chsc_get_channel_measurement_chars(struct channel_path *chp); diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 6da84543dfe9..651976b54af8 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -686,6 +686,46 @@ int ccw_device_tm_start_timeout(struct ccw_device *cdev, struct tcw *tcw, } EXPORT_SYMBOL(ccw_device_tm_start_timeout); +/** + * ccw_device_get_mdc - accumulate max data count + * @cdev: ccw device for which the max data count is accumulated + * @mask: mask of paths to use + * + * Return the number of 64K-bytes blocks all paths at least support + * for a transport command. Return values <= 0 indicate failures. + */ +int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask) +{ + struct subchannel *sch = to_subchannel(cdev->dev.parent); + struct channel_path_desc_fmt1 desc; + struct chp_id chpid; + int mdc = 0, ret, i; + + /* Adjust requested path mask to excluded varied off paths. */ + if (mask) + mask &= sch->lpm; + else + mask = sch->lpm; + + chp_id_init(&chpid); + for (i = 0; i < 8; i++) { + if (!(mask & (0x80 >> i))) + continue; + chpid.id = sch->schib.pmcw.chpid[i]; + ret = chsc_determine_fmt1_channel_path_desc(chpid, &desc); + if (ret) + return ret; + if (!desc.f) + return 0; + if (!desc.r) + mdc = 1; + mdc = mdc ? min(mdc, (int)desc.mdc) : desc.mdc; + } + + return mdc; +} +EXPORT_SYMBOL(ccw_device_get_mdc); + /** * ccw_device_tm_intrg - perform interrogate function * @cdev: ccw device on which to perform the interrogate function -- cgit v1.2.3 From 4bc4e965d3e86897e4c7c487a477ccdf13db5b82 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 5 Jan 2011 12:47:58 +0100 Subject: [S390] css: update subchannel descriptor Update the subchannel descriptor if we receive a "Installed parameters modified" crw. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 825951b6b83f..24d8e97355b9 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -618,6 +618,7 @@ EXPORT_SYMBOL_GPL(css_schedule_reprobe); static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) { struct subchannel_id mchk_schid; + struct subchannel *sch; if (overflow) { css_schedule_eval_all(); @@ -637,6 +638,13 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) if (crw1) mchk_schid.ssid = (crw1->rsid >> 4) & 3; + if (crw0->erc == CRW_ERC_PMOD) { + sch = get_subchannel_by_schid(mchk_schid); + if (sch) { + css_update_ssd_info(sch); + put_device(&sch->dev); + } + } /* * Since we are always presented with IPI in the CRW, we have to * use stsch() to find out if the subchannel in question has come -- cgit v1.2.3 From aa3a41d009d433dd9775b356b2d70551816f1f3c Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 5 Jan 2011 12:47:59 +0100 Subject: [S390] qeth: buffer count imbalance The used buffers counter is not incremented in case of an error so the counter can become negative. Increment the used buffers counter before checking for errors. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/net/qeth_core_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index f65320babf71..29f848bfc12f 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2840,6 +2840,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() - queue->card->perf_stats.outbound_do_qdio_start_time; + atomic_add(count, &queue->used_buffers); if (rc) { queue->card->stats.tx_errors += count; /* ignore temporary SIGA errors without busy condition */ @@ -2853,7 +2854,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, qeth_schedule_recovery(queue->card); return; } - atomic_add(count, &queue->used_buffers); if (queue->card->options.performance_stats) queue->card->perf_stats.bufs_sent += count; } -- cgit v1.2.3 From 9062014cb60194630272709da82d5879d563865e Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Wed, 5 Jan 2011 12:48:01 +0100 Subject: [S390] cio: reduce memory consumption of itcw structures Any list of indirect data adresses (TIDAL) used by a TCW must not cross a page boundary. The original itcw implementation complies with this restriction by allocating allmost twice as much memory as actually needed, so that in any case there is enough room for the full TIDAL, either above or below the page boundary. This patch implements an alternative method, by using a TTIC TIDAW to connect TIDAL parts below and above a page boundary. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/itcw.c | 62 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 10 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/itcw.c b/drivers/s390/cio/itcw.c index a0ae29564774..358ee16d10a2 100644 --- a/drivers/s390/cio/itcw.c +++ b/drivers/s390/cio/itcw.c @@ -93,6 +93,7 @@ EXPORT_SYMBOL(itcw_get_tcw); size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws) { size_t len; + int cross_count; /* Main data. */ len = sizeof(struct itcw); @@ -105,12 +106,27 @@ size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws) /* TSB */ sizeof(struct tsb) + /* TIDAL */ intrg_max_tidaws * sizeof(struct tidaw); } + /* Maximum required alignment padding. */ len += /* Initial TCW */ 63 + /* Interrogate TCCB */ 7; - /* Maximum padding for structures that may not cross 4k boundary. */ - if ((max_tidaws > 0) || (intrg_max_tidaws > 0)) - len += max(max_tidaws, intrg_max_tidaws) * - sizeof(struct tidaw) - 1; + + /* TIDAW lists may not cross a 4k boundary. To cross a + * boundary we need to add a TTIC TIDAW. We need to reserve + * one additional TIDAW for a TTIC that we may need to add due + * to the placement of the data chunk in memory, and a further + * TIDAW for each page boundary that the TIDAW list may cross + * due to it's own size. + */ + if (max_tidaws) { + cross_count = 1 + ((max_tidaws * sizeof(struct tidaw) - 1) + >> PAGE_SHIFT); + len += cross_count * sizeof(struct tidaw); + } + if (intrg_max_tidaws) { + cross_count = 1 + ((intrg_max_tidaws * sizeof(struct tidaw) - 1) + >> PAGE_SHIFT); + len += cross_count * sizeof(struct tidaw); + } return len; } EXPORT_SYMBOL(itcw_calc_size); @@ -165,6 +181,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg, void *chunk; addr_t start; addr_t end; + int cross_count; /* Check for 2G limit. */ start = (addr_t) buffer; @@ -177,8 +194,17 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg, if (IS_ERR(chunk)) return chunk; itcw = chunk; - itcw->max_tidaws = max_tidaws; - itcw->intrg_max_tidaws = intrg_max_tidaws; + /* allow for TTIC tidaws that may be needed to cross a page boundary */ + cross_count = 0; + if (max_tidaws) + cross_count = 1 + ((max_tidaws * sizeof(struct tidaw) - 1) + >> PAGE_SHIFT); + itcw->max_tidaws = max_tidaws + cross_count; + cross_count = 0; + if (intrg_max_tidaws) + cross_count = 1 + ((intrg_max_tidaws * sizeof(struct tidaw) - 1) + >> PAGE_SHIFT); + itcw->intrg_max_tidaws = intrg_max_tidaws + cross_count; /* Main TCW. */ chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0); if (IS_ERR(chunk)) @@ -198,7 +224,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg, /* Data TIDAL. */ if (max_tidaws > 0) { chunk = fit_chunk(&start, end, sizeof(struct tidaw) * - max_tidaws, 16, 1); + itcw->max_tidaws, 16, 0); if (IS_ERR(chunk)) return chunk; tcw_set_data(itcw->tcw, chunk, 1); @@ -206,7 +232,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg, /* Interrogate data TIDAL. */ if (intrg && (intrg_max_tidaws > 0)) { chunk = fit_chunk(&start, end, sizeof(struct tidaw) * - intrg_max_tidaws, 16, 1); + itcw->intrg_max_tidaws, 16, 0); if (IS_ERR(chunk)) return chunk; tcw_set_data(itcw->intrg_tcw, chunk, 1); @@ -283,13 +309,29 @@ EXPORT_SYMBOL(itcw_add_dcw); * the new tidaw on success or -%ENOSPC if the new tidaw would exceed the * available space. * - * Note: the tidaw-list is assumed to be contiguous with no ttics. The - * last-tidaw flag for the last tidaw in the list will be set by itcw_finalize. + * Note: TTIC tidaws are automatically added when needed, so explicitly calling + * this interface with the TTIC flag is not supported. The last-tidaw flag + * for the last tidaw in the list will be set by itcw_finalize. */ struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr, u32 count) { + struct tidaw *following; + if (itcw->num_tidaws >= itcw->max_tidaws) return ERR_PTR(-ENOSPC); + /* + * Is the tidaw, which follows the one we are about to fill, on the next + * page? Then we have to insert a TTIC tidaw first, that points to the + * tidaw on the new page. + */ + following = ((struct tidaw *) tcw_get_data(itcw->tcw)) + + itcw->num_tidaws + 1; + if (itcw->num_tidaws && !((unsigned long) following & ~PAGE_MASK)) { + tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++, + TIDAW_FLAGS_TTIC, following, 0); + if (itcw->num_tidaws >= itcw->max_tidaws) + return ERR_PTR(-ENOSPC); + } return tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++, flags, addr, count); } EXPORT_SYMBOL(itcw_add_tidaw); -- cgit v1.2.3 From ef19298b406f93af4bb249f0776deb8366e97532 Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Wed, 5 Jan 2011 12:48:02 +0100 Subject: [S390] dasd: add High Performance FICON multitrack support Some storage systems support multitrack High Performance FICON requests, which read or write data to more than one track. This patch enables the DASD device driver to generate multitrack High Performance FICON requests. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 4 -- drivers/s390/block/dasd_eckd.c | 158 ++++++++++++++++++++++++++++++----------- drivers/s390/block/dasd_eckd.h | 6 ++ 3 files changed, 122 insertions(+), 46 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index faa7d425cb9c..605f96f154a5 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -745,10 +745,6 @@ struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, char *data; int size; - /* Sanity checks */ - BUG_ON(datasize > PAGE_SIZE || - (cplength*sizeof(struct ccw1)) > PAGE_SIZE); - size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; if (cplength > 0) size += cplength * sizeof(struct ccw1); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index bf61274af3bb..549443af121c 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1105,6 +1105,37 @@ static void dasd_eckd_validate_server(struct dasd_device *device) "returned rc=%d", private->uid.ssid, rc); } +static u32 get_fcx_max_data(struct dasd_device *device) +{ +#if defined(CONFIG_64BIT) + int tpm, mdc; + int fcx_in_css, fcx_in_gneq, fcx_in_features; + struct dasd_eckd_private *private; + + if (dasd_nofcx) + return 0; + /* is transport mode supported? */ + private = (struct dasd_eckd_private *) device->private; + fcx_in_css = css_general_characteristics.fcx; + fcx_in_gneq = private->gneq->reserved2[7] & 0x04; + fcx_in_features = private->features.feature[40] & 0x80; + tpm = fcx_in_css && fcx_in_gneq && fcx_in_features; + + if (!tpm) + return 0; + + mdc = ccw_device_get_mdc(device->cdev, 0); + if (mdc < 0) { + dev_warn(&device->cdev->dev, "Detecting the maximum supported" + " data size for zHPF requests failed\n"); + return 0; + } else + return mdc * FCX_MAX_DATA_FACTOR; +#else + return 0; +#endif +} + /* * Check device characteristics. * If the device is accessible using ECKD discipline, the device is enabled. @@ -1223,6 +1254,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device) else private->real_cyl = private->rdc_data.no_cyl; + private->fcx_max_data = get_fcx_max_data(device); + readonly = dasd_device_is_ro(device); if (readonly) set_bit(DASD_FLAG_DEVICE_RO, &device->flags); @@ -2326,6 +2359,12 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( struct tidaw *last_tidaw = NULL; int itcw_op; size_t itcw_size; + u8 tidaw_flags; + unsigned int seg_len, part_len, len_to_track_end; + unsigned char new_track; + sector_t recid, trkid; + unsigned int offs; + unsigned int count, count_to_trk_end; basedev = block->base; private = (struct dasd_eckd_private *) basedev->private; @@ -2341,12 +2380,16 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( /* trackbased I/O needs address all memory via TIDAWs, * not just for 64 bit addresses. This allows us to map * each segment directly to one tidaw. + * In the case of write requests, additional tidaws may + * be needed when a segment crosses a track boundary. */ trkcount = last_trk - first_trk + 1; ctidaw = 0; rq_for_each_segment(bv, req, iter) { ++ctidaw; } + if (rq_data_dir(req) == WRITE) + ctidaw += (last_trk - first_trk); /* Allocate the ccw request. */ itcw_size = itcw_calc_size(0, ctidaw, 0); @@ -2354,15 +2397,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( if (IS_ERR(cqr)) return cqr; - cqr->cpmode = 1; - cqr->startdev = startdev; - cqr->memdev = startdev; - cqr->block = block; - cqr->expires = 100*HZ; - cqr->buildclk = get_clock(); - cqr->status = DASD_CQR_FILLED; - cqr->retries = 10; - /* transfer length factor: how many bytes to read from the last track */ if (first_trk == last_trk) tlf = last_offs - first_offs + 1; @@ -2371,8 +2405,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( tlf *= blksize; itcw = itcw_init(cqr->data, itcw_size, itcw_op, 0, ctidaw, 0); + if (IS_ERR(itcw)) { + dasd_sfree_request(cqr, startdev); + return ERR_PTR(-EINVAL); + } cqr->cpaddr = itcw_get_tcw(itcw); - if (prepare_itcw(itcw, first_trk, last_trk, cmd, basedev, startdev, first_offs + 1, @@ -2385,26 +2422,64 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( dasd_sfree_request(cqr, startdev); return ERR_PTR(-EAGAIN); } - /* * A tidaw can address 4k of memory, but must not cross page boundaries * We can let the block layer handle this by setting * blk_queue_segment_boundary to page boundaries and * blk_max_segment_size to page size when setting up the request queue. + * For write requests, a TIDAW must not cross track boundaries, because + * we have to set the CBC flag on the last tidaw for each track. */ - rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - last_tidaw = itcw_add_tidaw(itcw, 0x00, dst, bv->bv_len); - if (IS_ERR(last_tidaw)) - return (struct dasd_ccw_req *)last_tidaw; + if (rq_data_dir(req) == WRITE) { + new_track = 1; + recid = first_rec; + rq_for_each_segment(bv, req, iter) { + dst = page_address(bv->bv_page) + bv->bv_offset; + seg_len = bv->bv_len; + while (seg_len) { + if (new_track) { + trkid = recid; + offs = sector_div(trkid, blk_per_trk); + count_to_trk_end = blk_per_trk - offs; + count = min((last_rec - recid + 1), + (sector_t)count_to_trk_end); + len_to_track_end = count * blksize; + recid += count; + new_track = 0; + } + part_len = min(seg_len, len_to_track_end); + seg_len -= part_len; + len_to_track_end -= part_len; + /* We need to end the tidaw at track end */ + if (!len_to_track_end) { + new_track = 1; + tidaw_flags = TIDAW_FLAGS_INSERT_CBC; + } else + tidaw_flags = 0; + last_tidaw = itcw_add_tidaw(itcw, tidaw_flags, + dst, part_len); + if (IS_ERR(last_tidaw)) + return ERR_PTR(-EINVAL); + dst += part_len; + } + } + } else { + rq_for_each_segment(bv, req, iter) { + dst = page_address(bv->bv_page) + bv->bv_offset; + last_tidaw = itcw_add_tidaw(itcw, 0x00, + dst, bv->bv_len); + if (IS_ERR(last_tidaw)) + return ERR_PTR(-EINVAL); + } } - - last_tidaw->flags |= 0x80; + last_tidaw->flags |= TIDAW_FLAGS_LAST; + last_tidaw->flags &= ~TIDAW_FLAGS_INSERT_CBC; itcw_finalize(itcw); if (blk_noretry_request(req) || block->base->features & DASD_FEATURE_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->cpmode = 1; cqr->startdev = startdev; cqr->memdev = startdev; cqr->block = block; @@ -2420,11 +2495,9 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, struct dasd_block *block, struct request *req) { - int tpm, cmdrtd, cmdwtd; + int cmdrtd, cmdwtd; int use_prefix; -#if defined(CONFIG_64BIT) - int fcx_in_css, fcx_in_gneq, fcx_in_features; -#endif + int fcx_multitrack; struct dasd_eckd_private *private; struct dasd_device *basedev; sector_t first_rec, last_rec; @@ -2432,6 +2505,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, unsigned int first_offs, last_offs; unsigned int blk_per_trk, blksize; int cdlspecial; + unsigned int data_size; struct dasd_ccw_req *cqr; basedev = block->base; @@ -2450,15 +2524,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, last_offs = sector_div(last_trk, blk_per_trk); cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk); - /* is transport mode supported? */ -#if defined(CONFIG_64BIT) - fcx_in_css = css_general_characteristics.fcx; - fcx_in_gneq = private->gneq->reserved2[7] & 0x04; - fcx_in_features = private->features.feature[40] & 0x80; - tpm = fcx_in_css && fcx_in_gneq && fcx_in_features; -#else - tpm = 0; -#endif + fcx_multitrack = private->features.feature[40] & 0x20; + data_size = blk_rq_bytes(req); + /* tpm write request add CBC data on each track boundary */ + if (rq_data_dir(req) == WRITE) + data_size += (last_trk - first_trk) * 4; /* is read track data and write track data in command mode supported? */ cmdrtd = private->features.feature[9] & 0x20; @@ -2468,13 +2538,15 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, cqr = NULL; if (cdlspecial || dasd_page_cache) { /* do nothing, just fall through to the cmd mode single case */ - } else if (!dasd_nofcx && tpm && (first_trk == last_trk)) { + } else if ((data_size <= private->fcx_max_data) + && (fcx_multitrack || (first_trk == last_trk))) { cqr = dasd_eckd_build_cp_tpm_track(startdev, block, req, first_rec, last_rec, first_trk, last_trk, first_offs, last_offs, blk_per_trk, blksize); - if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) + if (IS_ERR(cqr) && (PTR_ERR(cqr) != -EAGAIN) && + (PTR_ERR(cqr) != -ENOMEM)) cqr = NULL; } else if (use_prefix && (((rq_data_dir(req) == READ) && cmdrtd) || @@ -2484,7 +2556,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, first_trk, last_trk, first_offs, last_offs, blk_per_trk, blksize); - if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) + if (IS_ERR(cqr) && (PTR_ERR(cqr) != -EAGAIN) && + (PTR_ERR(cqr) != -ENOMEM)) cqr = NULL; } if (!cqr) @@ -3279,10 +3352,8 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, { char *page; int len, sl, sct, residual; - struct tsb *tsb; - u8 *sense; - + u8 *sense, *rcq; page = (char *) get_zeroed_page(GFP_ATOMIC); if (page == NULL) { @@ -3348,12 +3419,15 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, case 2: /* ts_ddpc */ len += sprintf(page + len, KERN_ERR PRINTK_HEADER " tsb->tsa.ddpc.rc %d\n", tsb->tsa.ddpc.rc); - len += sprintf(page + len, KERN_ERR PRINTK_HEADER - " tsb->tsa.ddpc.rcq: "); - for (sl = 0; sl < 16; sl++) { + for (sl = 0; sl < 2; sl++) { + len += sprintf(page + len, + KERN_ERR PRINTK_HEADER + " tsb->tsa.ddpc.rcq %2d-%2d: ", + (8 * sl), ((8 * sl) + 7)); + rcq = tsb->tsa.ddpc.rcq; for (sct = 0; sct < 8; sct++) { len += sprintf(page + len, " %02x", - tsb->tsa.ddpc.rcq[sl]); + rcq[8 * sl + sct]); } len += sprintf(page + len, "\n"); } @@ -3573,7 +3647,7 @@ static struct dasd_discipline dasd_eckd_discipline = { .owner = THIS_MODULE, .name = "ECKD", .ebcname = "ECKD", - .max_blocks = 240, + .max_blocks = 190, .check_device = dasd_eckd_check_characteristics, .uncheck_device = dasd_eckd_uncheck_device, .do_analysis = dasd_eckd_do_analysis, diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 12097c24f2f5..2150aed541be 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -57,6 +57,10 @@ */ #define LV_COMPAT_CYL 0xFFFE + +#define FCX_MAX_DATA_FACTOR 65536 + + /***************************************************************************** * SECTION: Type Definitions ****************************************************************************/ @@ -455,6 +459,8 @@ struct dasd_eckd_private { struct alias_pav_group *pavgroup; struct alias_lcu *lcu; int count; + + u32 fcx_max_data; }; -- cgit v1.2.3 From a4d26c6aeceea330ee5e0fb6b017d57e3b252d29 Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Wed, 5 Jan 2011 12:48:03 +0100 Subject: [S390] dasd: do path verification for paths added at runtime When a new path is added at runtime, the CIO layer will call the drivers path_event callback. The DASD device driver uses this callback to trigger a path verification for the new path. The driver will use only those paths for I/O, which have been successfully verified. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 202 +++++++++++++++++++++------- drivers/s390/block/dasd_3990_erp.c | 16 +-- drivers/s390/block/dasd_devmap.c | 1 + drivers/s390/block/dasd_diag.c | 1 + drivers/s390/block/dasd_eckd.c | 261 +++++++++++++++++++++++++++++++------ drivers/s390/block/dasd_eckd.h | 9 +- drivers/s390/block/dasd_erp.c | 3 +- drivers/s390/block/dasd_fba.c | 3 + drivers/s390/block/dasd_int.h | 22 ++++ 9 files changed, 418 insertions(+), 100 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 605f96f154a5..8f2067bc88c0 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -913,6 +913,11 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) cqr->startclk = get_clock(); cqr->starttime = jiffies; cqr->retries--; + if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) { + cqr->lpm &= device->path_data.opm; + if (!cqr->lpm) + cqr->lpm = device->path_data.opm; + } if (cqr->cpmode == 1) { rc = ccw_device_tm_start(device->cdev, cqr->cpaddr, (long) cqr, cqr->lpm); @@ -925,35 +930,53 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) cqr->status = DASD_CQR_IN_IO; break; case -EBUSY: - DBF_DEV_EVENT(DBF_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "start_IO: device busy, retry later"); break; case -ETIMEDOUT: - DBF_DEV_EVENT(DBF_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "start_IO: request timeout, retry later"); break; case -EACCES: - /* -EACCES indicates that the request used only a - * subset of the available pathes and all these - * pathes are gone. - * Do a retry with all available pathes. + /* -EACCES indicates that the request used only a subset of the + * available paths and all these paths are gone. If the lpm of + * this request was only a subset of the opm (e.g. the ppm) then + * we just do a retry with all available paths. + * If we already use the full opm, something is amiss, and we + * need a full path verification. */ - cqr->lpm = LPM_ANYPATH; - DBF_DEV_EVENT(DBF_DEBUG, device, "%s", - "start_IO: selected pathes gone," - " retry on all pathes"); + if (test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) { + DBF_DEV_EVENT(DBF_WARNING, device, + "start_IO: selected paths gone (%x)", + cqr->lpm); + } else if (cqr->lpm != device->path_data.opm) { + cqr->lpm = device->path_data.opm; + DBF_DEV_EVENT(DBF_DEBUG, device, "%s", + "start_IO: selected paths gone," + " retry on all paths"); + } else { + DBF_DEV_EVENT(DBF_WARNING, device, "%s", + "start_IO: all paths in opm gone," + " do path verification"); + dasd_generic_last_path_gone(device); + device->path_data.opm = 0; + device->path_data.ppm = 0; + device->path_data.npm = 0; + device->path_data.tbvpm = + ccw_device_get_path_mask(device->cdev); + } break; case -ENODEV: - DBF_DEV_EVENT(DBF_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "start_IO: -ENODEV device gone, retry"); break; case -EIO: - DBF_DEV_EVENT(DBF_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "start_IO: -EIO device gone, retry"); break; case -EINVAL: /* most likely caused in power management context */ - DBF_DEV_EVENT(DBF_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "start_IO: -EINVAL device currently " "not accessible"); break; @@ -1175,12 +1198,13 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, */ if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && cqr->retries > 0) { - if (cqr->lpm == LPM_ANYPATH) + if (cqr->lpm == device->path_data.opm) DBF_DEV_EVENT(DBF_DEBUG, device, "default ERP in fastpath " "(%i retries left)", cqr->retries); - cqr->lpm = LPM_ANYPATH; + if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) + cqr->lpm = device->path_data.opm; cqr->status = DASD_CQR_QUEUED; next = cqr; } else @@ -1364,8 +1388,14 @@ static void __dasd_device_start_head(struct dasd_device *device) cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); if (cqr->status != DASD_CQR_QUEUED) return; - /* when device is stopped, return request to previous layer */ - if (device->stopped) { + /* when device is stopped, return request to previous layer + * exception: only the disconnect or unresumed bits are set and the + * cqr is a path verification request + */ + if (device->stopped && + !(!(device->stopped & ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM)) + && test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))) { + cqr->intrc = -EAGAIN; cqr->status = DASD_CQR_CLEARED; dasd_schedule_device_bh(device); return; @@ -1381,6 +1411,23 @@ static void __dasd_device_start_head(struct dasd_device *device) dasd_device_set_timer(device, 50); } +static void __dasd_device_check_path_events(struct dasd_device *device) +{ + int rc; + + if (device->path_data.tbvpm) { + if (device->stopped & ~(DASD_STOPPED_DC_WAIT | + DASD_UNRESUMED_PM)) + return; + rc = device->discipline->verify_path( + device, device->path_data.tbvpm); + if (rc) + dasd_device_set_timer(device, 50); + else + device->path_data.tbvpm = 0; + } +}; + /* * Go through all request on the dasd_device request queue, * terminate them on the cdev if necessary, and return them to the @@ -1455,6 +1502,7 @@ static void dasd_device_tasklet(struct dasd_device *device) __dasd_device_check_expire(device); /* find final requests on ccw queue */ __dasd_device_process_ccw_queue(device, &final_queue); + __dasd_device_check_path_events(device); spin_unlock_irq(get_ccwdev_lock(device->cdev)); /* Now call the callback function of requests with final status */ __dasd_device_process_final_queue(device, &final_queue); @@ -2586,10 +2634,53 @@ int dasd_generic_set_offline(struct ccw_device *cdev) return 0; } +int dasd_generic_last_path_gone(struct dasd_device *device) +{ + struct dasd_ccw_req *cqr; + + dev_warn(&device->cdev->dev, "No operational channel path is left " + "for the device\n"); + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "last path gone"); + /* First of all call extended error reporting. */ + dasd_eer_write(device, NULL, DASD_EER_NOPATH); + + if (device->state < DASD_STATE_BASIC) + return 0; + /* Device is active. We want to keep it. */ + list_for_each_entry(cqr, &device->ccw_queue, devlist) + if ((cqr->status == DASD_CQR_IN_IO) || + (cqr->status == DASD_CQR_CLEAR_PENDING)) { + cqr->status = DASD_CQR_QUEUED; + cqr->retries++; + } + dasd_device_set_stop_bits(device, DASD_STOPPED_DC_WAIT); + dasd_device_clear_timer(device); + dasd_schedule_device_bh(device); + return 1; +} +EXPORT_SYMBOL_GPL(dasd_generic_last_path_gone); + +int dasd_generic_path_operational(struct dasd_device *device) +{ + dev_info(&device->cdev->dev, "A channel path to the device has become " + "operational\n"); + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "path operational"); + dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT); + if (device->stopped & DASD_UNRESUMED_PM) { + dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM); + dasd_restore_device(device); + return 1; + } + dasd_schedule_device_bh(device); + if (device->block) + dasd_schedule_block_bh(device->block); + return 1; +} +EXPORT_SYMBOL_GPL(dasd_generic_path_operational); + int dasd_generic_notify(struct ccw_device *cdev, int event) { struct dasd_device *device; - struct dasd_ccw_req *cqr; int ret; device = dasd_device_from_cdev_locked(cdev); @@ -2600,41 +2691,64 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) case CIO_GONE: case CIO_BOXED: case CIO_NO_PATH: - /* First of all call extended error reporting. */ - dasd_eer_write(device, NULL, DASD_EER_NOPATH); - - if (device->state < DASD_STATE_BASIC) - break; - /* Device is active. We want to keep it. */ - list_for_each_entry(cqr, &device->ccw_queue, devlist) - if (cqr->status == DASD_CQR_IN_IO) { - cqr->status = DASD_CQR_QUEUED; - cqr->retries++; - } - dasd_device_set_stop_bits(device, DASD_STOPPED_DC_WAIT); - dasd_device_clear_timer(device); - dasd_schedule_device_bh(device); - ret = 1; + device->path_data.opm = 0; + device->path_data.ppm = 0; + device->path_data.npm = 0; + ret = dasd_generic_last_path_gone(device); break; case CIO_OPER: - /* FIXME: add a sanity check. */ - dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT); - if (device->stopped & DASD_UNRESUMED_PM) { - dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM); - dasd_restore_device(device); - ret = 1; - break; - } - dasd_schedule_device_bh(device); - if (device->block) - dasd_schedule_block_bh(device->block); ret = 1; + if (device->path_data.opm) + ret = dasd_generic_path_operational(device); break; } dasd_put_device(device); return ret; } +void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) +{ + int chp; + __u8 oldopm, eventlpm; + struct dasd_device *device; + + device = dasd_device_from_cdev_locked(cdev); + if (IS_ERR(device)) + return; + for (chp = 0; chp < 8; chp++) { + eventlpm = 0x80 >> chp; + if (path_event[chp] & PE_PATH_GONE) { + oldopm = device->path_data.opm; + device->path_data.opm &= ~eventlpm; + device->path_data.ppm &= ~eventlpm; + device->path_data.npm &= ~eventlpm; + if (oldopm && !device->path_data.opm) + dasd_generic_last_path_gone(device); + } + if (path_event[chp] & PE_PATH_AVAILABLE) { + device->path_data.opm &= ~eventlpm; + device->path_data.ppm &= ~eventlpm; + device->path_data.npm &= ~eventlpm; + device->path_data.tbvpm |= eventlpm; + dasd_schedule_device_bh(device); + } + } + dasd_put_device(device); +} +EXPORT_SYMBOL_GPL(dasd_generic_path_event); + +int dasd_generic_verify_path(struct dasd_device *device, __u8 lpm) +{ + if (!device->path_data.opm && lpm) { + device->path_data.opm = lpm; + dasd_generic_path_operational(device); + } else + device->path_data.opm |= lpm; + return 0; +} +EXPORT_SYMBOL_GPL(dasd_generic_verify_path); + + int dasd_generic_pm_freeze(struct ccw_device *cdev) { struct dasd_ccw_req *cqr, *n; diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 968c76cf7127..1654a24817be 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -152,9 +152,9 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); opm = ccw_device_get_path_mask(device->cdev); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); - //FIXME: start with get_opm ? if (erp->lpm == 0) - erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum); + erp->lpm = device->path_data.opm & + ~(erp->irb.esw.esw0.sublog.lpum); else erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum); @@ -270,10 +270,11 @@ static struct dasd_ccw_req *dasd_3990_erp_action_1(struct dasd_ccw_req *erp) { erp->function = dasd_3990_erp_action_1; dasd_3990_erp_alternate_path(erp); - if (erp->status == DASD_CQR_FAILED) { + if (erp->status == DASD_CQR_FAILED && + !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) { erp->status = DASD_CQR_FILLED; erp->retries = 10; - erp->lpm = LPM_ANYPATH; + erp->lpm = erp->startdev->path_data.opm; erp->function = dasd_3990_erp_action_1_sec; } return erp; @@ -1907,15 +1908,14 @@ dasd_3990_erp_compound_retry(struct dasd_ccw_req * erp, char *sense) static void dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense) { - if (sense[25] & DASD_SENSE_BIT_3) { dasd_3990_erp_alternate_path(erp); - if (erp->status == DASD_CQR_FAILED) { + if (erp->status == DASD_CQR_FAILED && + !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) { /* reset the lpm and the status to be able to * try further actions. */ - - erp->lpm = 0; + erp->lpm = erp->startdev->path_data.opm; erp->status = DASD_CQR_NEED_ERP; } } diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 8d41f3ed38d7..0001df8ad3e6 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -639,6 +639,7 @@ dasd_put_device_wake(struct dasd_device *device) { wake_up(&dasd_delete_wq); } +EXPORT_SYMBOL_GPL(dasd_put_device_wake); /* * Return dasd_device structure associated with cdev. diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index a3a5db58df18..29143eda9dd9 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -619,6 +619,7 @@ static struct dasd_discipline dasd_diag_discipline = { .ebcname = "DIAG", .max_blocks = DIAG_MAX_BLOCKS, .check_device = dasd_diag_check_device, + .verify_path = dasd_generic_verify_path, .fill_geometry = dasd_diag_fill_geometry, .start_IO = dasd_start_diag, .term_IO = dasd_diag_term_IO, diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 549443af121c..a1ebf5722ae5 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -90,6 +90,18 @@ static struct { } *dasd_reserve_req; static DEFINE_MUTEX(dasd_reserve_mutex); +/* definitions for the path verification worker */ +struct path_verification_work_data { + struct work_struct worker; + struct dasd_device *device; + struct dasd_ccw_req cqr; + struct ccw1 ccw; + __u8 rcd_buffer[DASD_ECKD_RCD_DATA_SIZE]; + int isglobal; + __u8 tbvpm; +}; +static struct path_verification_work_data *path_verification_worker; +static DEFINE_MUTEX(dasd_path_verification_mutex); /* initial attempt at a probe function. this can be simplified once * the other detection code is gone */ @@ -755,26 +767,27 @@ static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid) return -EINVAL; } -static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, - void *rcd_buffer, - struct ciw *ciw, __u8 lpm) +static void dasd_eckd_fill_rcd_cqr(struct dasd_device *device, + struct dasd_ccw_req *cqr, + __u8 *rcd_buffer, + __u8 lpm) { - struct dasd_ccw_req *cqr; struct ccw1 *ccw; - - cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* RCD */, ciw->count, - device); - - if (IS_ERR(cqr)) { - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "Could not allocate RCD request"); - return cqr; - } + /* + * buffer has to start with EBCDIC "V1.0" to show + * support for virtual device SNEQ + */ + rcd_buffer[0] = 0xE5; + rcd_buffer[1] = 0xF1; + rcd_buffer[2] = 0x4B; + rcd_buffer[3] = 0xF0; ccw = cqr->cpaddr; - ccw->cmd_code = ciw->cmd; + ccw->cmd_code = DASD_ECKD_CCW_RCD; + ccw->flags = 0; ccw->cda = (__u32)(addr_t)rcd_buffer; - ccw->count = ciw->count; + ccw->count = DASD_ECKD_RCD_DATA_SIZE; + cqr->magic = DASD_ECKD_MAGIC; cqr->startdev = device; cqr->memdev = device; @@ -784,7 +797,29 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, cqr->retries = 256; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; - return cqr; + set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags); +} + +static int dasd_eckd_read_conf_immediately(struct dasd_device *device, + struct dasd_ccw_req *cqr, + __u8 *rcd_buffer, + __u8 lpm) +{ + struct ciw *ciw; + int rc; + /* + * sanity check: scan for RCD command in extended SenseID data + * some devices do not support RCD + */ + ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD); + if (!ciw || ciw->cmd != DASD_ECKD_CCW_RCD) + return -EOPNOTSUPP; + + dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buffer, lpm); + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + cqr->retries = 5; + rc = dasd_sleep_on_immediatly(cqr); + return rc; } static int dasd_eckd_read_conf_lpm(struct dasd_device *device, @@ -797,32 +832,29 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, struct dasd_ccw_req *cqr; /* - * scan for RCD command in extended SenseID data + * sanity check: scan for RCD command in extended SenseID data + * some devices do not support RCD */ ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD); - if (!ciw || ciw->cmd == 0) { + if (!ciw || ciw->cmd != DASD_ECKD_CCW_RCD) { ret = -EOPNOTSUPP; goto out_error; } - rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA); + rcd_buf = kzalloc(DASD_ECKD_RCD_DATA_SIZE, GFP_KERNEL | GFP_DMA); if (!rcd_buf) { ret = -ENOMEM; goto out_error; } - - /* - * buffer has to start with EBCDIC "V1.0" to show - * support for virtual device SNEQ - */ - rcd_buf[0] = 0xE5; - rcd_buf[1] = 0xF1; - rcd_buf[2] = 0x4B; - rcd_buf[3] = 0xF0; - cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* RCD */, + 0, /* use rcd_buf as data ara */ + device); if (IS_ERR(cqr)) { - ret = PTR_ERR(cqr); + DBF_DEV_EVENT(DBF_WARNING, device, "%s", + "Could not allocate RCD request"); + ret = -ENOMEM; goto out_error; } + dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buf, lpm); ret = dasd_sleep_on(cqr); /* * on success we update the user input parms @@ -831,7 +863,7 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, if (ret) goto out_error; - *rcd_buffer_size = ciw->count; + *rcd_buffer_size = DASD_ECKD_RCD_DATA_SIZE; *rcd_buffer = rcd_buf; return 0; out_error: @@ -901,18 +933,18 @@ static int dasd_eckd_read_conf(struct dasd_device *device) void *conf_data; int conf_len, conf_data_saved; int rc; - __u8 lpm; + __u8 lpm, opm; struct dasd_eckd_private *private; - struct dasd_eckd_path *path_data; + struct dasd_path *path_data; private = (struct dasd_eckd_private *) device->private; - path_data = (struct dasd_eckd_path *) &private->path_data; - path_data->opm = ccw_device_get_path_mask(device->cdev); + path_data = &device->path_data; + opm = ccw_device_get_path_mask(device->cdev); lpm = 0x80; conf_data_saved = 0; /* get configuration data per operational path */ for (lpm = 0x80; lpm; lpm>>= 1) { - if (lpm & path_data->opm){ + if (lpm & opm) { rc = dasd_eckd_read_conf_lpm(device, &conf_data, &conf_len, lpm); if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */ @@ -925,6 +957,8 @@ static int dasd_eckd_read_conf(struct dasd_device *device) DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", "No configuration data " "retrieved"); + /* no further analysis possible */ + path_data->opm |= lpm; continue; /* no error */ } /* save first valid configuration data */ @@ -948,6 +982,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device) path_data->ppm |= lpm; break; } + path_data->opm |= lpm; if (conf_data != private->conf_data) kfree(conf_data); } @@ -955,6 +990,140 @@ static int dasd_eckd_read_conf(struct dasd_device *device) return 0; } +static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm) +{ + struct dasd_eckd_private *private; + int mdc; + u32 fcx_max_data; + + private = (struct dasd_eckd_private *) device->private; + if (private->fcx_max_data) { + mdc = ccw_device_get_mdc(device->cdev, lpm); + if ((mdc < 0)) { + dev_warn(&device->cdev->dev, + "Detecting the maximum data size for zHPF " + "requests failed (rc=%d) for a new path %x\n", + mdc, lpm); + return mdc; + } + fcx_max_data = mdc * FCX_MAX_DATA_FACTOR; + if (fcx_max_data < private->fcx_max_data) { + dev_warn(&device->cdev->dev, + "The maximum data size for zHPF requests %u " + "on a new path %x is below the active maximum " + "%u\n", fcx_max_data, lpm, + private->fcx_max_data); + return -EACCES; + } + } + return 0; +} + +static void do_path_verification_work(struct work_struct *work) +{ + struct path_verification_work_data *data; + struct dasd_device *device; + __u8 lpm, opm, npm, ppm, epm; + unsigned long flags; + int rc; + + data = container_of(work, struct path_verification_work_data, worker); + device = data->device; + + opm = 0; + npm = 0; + ppm = 0; + epm = 0; + for (lpm = 0x80; lpm; lpm >>= 1) { + if (lpm & data->tbvpm) { + memset(data->rcd_buffer, 0, sizeof(data->rcd_buffer)); + memset(&data->cqr, 0, sizeof(data->cqr)); + data->cqr.cpaddr = &data->ccw; + rc = dasd_eckd_read_conf_immediately(device, &data->cqr, + data->rcd_buffer, + lpm); + if (!rc) { + switch (dasd_eckd_path_access(data->rcd_buffer, + DASD_ECKD_RCD_DATA_SIZE)) { + case 0x02: + npm |= lpm; + break; + case 0x03: + ppm |= lpm; + break; + } + opm |= lpm; + } else if (rc == -EOPNOTSUPP) { + DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", + "path verification: No configuration " + "data retrieved"); + opm |= lpm; + } else if (rc == -EAGAIN) { + DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", + "path verification: device is stopped," + " try again later"); + epm |= lpm; + } else { + dev_warn(&device->cdev->dev, + "Reading device feature codes failed " + "(rc=%d) for new path %x\n", rc, lpm); + continue; + } + if (verify_fcx_max_data(device, lpm)) { + opm &= ~lpm; + npm &= ~lpm; + ppm &= ~lpm; + } + } + } + /* + * There is a small chance that a path is lost again between + * above path verification and the following modification of + * the device opm mask. We could avoid that race here by using + * yet another path mask, but we rather deal with this unlikely + * situation in dasd_start_IO. + */ + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + if (!device->path_data.opm && opm) { + device->path_data.opm = opm; + dasd_generic_path_operational(device); + } else + device->path_data.opm |= opm; + device->path_data.npm |= npm; + device->path_data.ppm |= ppm; + device->path_data.tbvpm |= epm; + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + + dasd_put_device(device); + if (data->isglobal) + mutex_unlock(&dasd_path_verification_mutex); + else + kfree(data); +} + +static int dasd_eckd_verify_path(struct dasd_device *device, __u8 lpm) +{ + struct path_verification_work_data *data; + + data = kmalloc(sizeof(*data), GFP_ATOMIC | GFP_DMA); + if (!data) { + if (mutex_trylock(&dasd_path_verification_mutex)) { + data = path_verification_worker; + data->isglobal = 1; + } else + return -ENOMEM; + } else { + memset(data, 0, sizeof(*data)); + data->isglobal = 0; + } + INIT_WORK(&data->worker, do_path_verification_work); + dasd_get_device(device); + data->device = device; + data->tbvpm = lpm; + schedule_work(&data->worker); + return 0; +} + static int dasd_eckd_read_features(struct dasd_device *device) { struct dasd_psf_prssd_data *prssdp; @@ -1749,6 +1918,7 @@ static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) if (cqr->block && (cqr->startdev != cqr->block->base)) { dasd_eckd_reset_ccw_to_base_io(cqr); cqr->startdev = cqr->block->base; + cqr->lpm = cqr->block->base->path_data.opm; } }; @@ -2017,7 +2187,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( cqr->memdev = startdev; cqr->block = block; cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ - cqr->lpm = private->path_data.ppm; + cqr->lpm = startdev->path_data.ppm; cqr->retries = 256; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -2194,7 +2364,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( cqr->memdev = startdev; cqr->block = block; cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ - cqr->lpm = private->path_data.ppm; + cqr->lpm = startdev->path_data.ppm; cqr->retries = 256; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -2484,7 +2654,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( cqr->memdev = startdev; cqr->block = block; cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ - cqr->lpm = private->path_data.ppm; + cqr->lpm = startdev->path_data.ppm; cqr->retries = 256; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -3624,6 +3794,7 @@ static struct ccw_driver dasd_eckd_driver = { .set_offline = dasd_generic_set_offline, .set_online = dasd_eckd_set_online, .notify = dasd_generic_notify, + .path_event = dasd_generic_path_event, .freeze = dasd_generic_pm_freeze, .thaw = dasd_generic_restore_device, .restore = dasd_generic_restore_device, @@ -3651,6 +3822,7 @@ static struct dasd_discipline dasd_eckd_discipline = { .check_device = dasd_eckd_check_characteristics, .uncheck_device = dasd_eckd_uncheck_device, .do_analysis = dasd_eckd_do_analysis, + .verify_path = dasd_eckd_verify_path, .ready_to_online = dasd_eckd_ready_to_online, .online_to_ready = dasd_eckd_online_to_ready, .fill_geometry = dasd_eckd_fill_geometry, @@ -3683,11 +3855,19 @@ dasd_eckd_init(void) GFP_KERNEL | GFP_DMA); if (!dasd_reserve_req) return -ENOMEM; + path_verification_worker = kmalloc(sizeof(*path_verification_worker), + GFP_KERNEL | GFP_DMA); + if (!path_verification_worker) { + kfree(dasd_reserve_req); + return -ENOMEM; + } ret = ccw_driver_register(&dasd_eckd_driver); if (!ret) wait_for_device_probe(); - else + else { + kfree(path_verification_worker); kfree(dasd_reserve_req); + } return ret; } @@ -3695,6 +3875,7 @@ static void __exit dasd_eckd_cleanup(void) { ccw_driver_unregister(&dasd_eckd_driver); + kfree(path_verification_worker); kfree(dasd_reserve_req); } diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 2150aed541be..5051f374cbcb 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -45,6 +45,7 @@ #define DASD_ECKD_CCW_PFX 0xE7 #define DASD_ECKD_CCW_PFX_READ 0xEA #define DASD_ECKD_CCW_RSCK 0xF9 +#define DASD_ECKD_CCW_RCD 0xFA /* * Perform Subsystem Function / Sub-Orders @@ -59,6 +60,7 @@ #define FCX_MAX_DATA_FACTOR 65536 +#define DASD_ECKD_RCD_DATA_SIZE 256 /***************************************************************************** @@ -335,12 +337,6 @@ struct dasd_gneq { __u8 reserved2[22]; } __attribute__ ((packed)); -struct dasd_eckd_path { - __u8 opm; - __u8 ppm; - __u8 npm; -}; - struct dasd_rssd_features { char feature[256]; } __attribute__((packed)); @@ -446,7 +442,6 @@ struct dasd_eckd_private { struct vd_sneq *vdsneq; struct dasd_gneq *gneq; - struct dasd_eckd_path path_data; struct eckd_count count_area[5]; int init_cqr_status; int uses_cdl; diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 7656384a811d..0eafe2e421e7 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -96,7 +96,8 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr) DBF_DEV_EVENT(DBF_DEBUG, device, "default ERP called (%i retries left)", cqr->retries); - cqr->lpm = LPM_ANYPATH; + if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) + cqr->lpm = device->path_data.opm; cqr->status = DASD_CQR_FILLED; } else { pr_err("%s: default ERP has run out of retries and failed\n", diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index bec5486e0e6d..86bacda2c5f6 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -73,6 +73,7 @@ static struct ccw_driver dasd_fba_driver = { .set_offline = dasd_generic_set_offline, .set_online = dasd_fba_set_online, .notify = dasd_generic_notify, + .path_event = dasd_generic_path_event, .freeze = dasd_generic_pm_freeze, .thaw = dasd_generic_restore_device, .restore = dasd_generic_restore_device, @@ -164,6 +165,7 @@ dasd_fba_check_characteristics(struct dasd_device *device) } device->default_expires = DASD_EXPIRES; + device->path_data.opm = LPM_ANYPATH; readonly = dasd_device_is_ro(device); if (readonly) @@ -596,6 +598,7 @@ static struct dasd_discipline dasd_fba_discipline = { .max_blocks = 96, .check_device = dasd_fba_check_characteristics, .do_analysis = dasd_fba_do_analysis, + .verify_path = dasd_generic_verify_path, .fill_geometry = dasd_fba_fill_geometry, .start_IO = dasd_start_IO, .term_IO = dasd_term_IO, diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 500678d7116c..ba038ef57606 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -231,6 +231,7 @@ struct dasd_ccw_req { /* per dasd_ccw_req flags */ #define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ #define DASD_CQR_FLAGS_FAILFAST 1 /* FAILFAST */ +#define DASD_CQR_VERIFY_PATH 2 /* path verification request */ /* Signature for error recovery functions. */ typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); @@ -286,6 +287,14 @@ struct dasd_discipline { */ int (*do_analysis) (struct dasd_block *); + /* + * This function is called, when new paths become available. + * Disciplins may use this callback to do necessary setup work, + * e.g. verify that new path is compatible with the current + * configuration. + */ + int (*verify_path)(struct dasd_device *, __u8); + /* * Last things to do when a device is set online, and first things * when it is set offline. @@ -362,6 +371,13 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer; #define DASD_EER_STATECHANGE 3 #define DASD_EER_PPRCSUSPEND 4 +struct dasd_path { + __u8 opm; + __u8 tbvpm; + __u8 ppm; + __u8 npm; +}; + struct dasd_device { /* Block device stuff. */ struct dasd_block *block; @@ -377,6 +393,7 @@ struct dasd_device { struct dasd_discipline *discipline; struct dasd_discipline *base_discipline; char *private; + struct dasd_path path_data; /* Device state and target state. */ int state, target; @@ -620,10 +637,15 @@ void dasd_generic_remove (struct ccw_device *cdev); int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); int dasd_generic_set_offline (struct ccw_device *cdev); int dasd_generic_notify(struct ccw_device *, int); +int dasd_generic_last_path_gone(struct dasd_device *); +int dasd_generic_path_operational(struct dasd_device *); + void dasd_generic_handle_state_change(struct dasd_device *); int dasd_generic_pm_freeze(struct ccw_device *); int dasd_generic_restore_device(struct ccw_device *); enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *); +void dasd_generic_path_event(struct ccw_device *, int *); +int dasd_generic_verify_path(struct dasd_device *, __u8); int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int); char *dasd_get_sense(struct irb *); -- cgit v1.2.3 From 5a27e60dec59a95bd7f8ae9a19ae2ede4f76395b Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Wed, 5 Jan 2011 12:48:04 +0100 Subject: [S390] dasd: Improve handling of stolen DASD reservation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a DASD device has been reserved by a Linux system, and later this reservation is ‘stolen’ by a second system by means of an unconditional reserve, then the first system receives a notification about this fact. With this patch such an event can be either ignored, as before, or it can be used to let the device fail all I/O request, so that the device will not block anymore. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/dasd.h | 1 + drivers/s390/block/dasd.c | 75 +++++++++++++++++------------- drivers/s390/block/dasd_devmap.c | 99 ++++++++++++++++++++++++++++++++++++++++ drivers/s390/block/dasd_eckd.c | 51 ++++++++++++--------- drivers/s390/block/dasd_eer.c | 1 + drivers/s390/block/dasd_fba.c | 18 ++------ drivers/s390/block/dasd_int.h | 13 ++++-- 7 files changed, 189 insertions(+), 69 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h index b604a9186f8e..47fcdada5d25 100644 --- a/arch/s390/include/asm/dasd.h +++ b/arch/s390/include/asm/dasd.h @@ -80,6 +80,7 @@ typedef struct dasd_information2_t { #define DASD_FEATURE_INITIAL_ONLINE 0x04 #define DASD_FEATURE_ERPLOG 0x08 #define DASD_FEATURE_FAILFAST 0x10 +#define DASD_FEATURE_FAILONSLCK 0x20 #define DASD_PARTN_BITS 2 diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 8f2067bc88c0..f16afe74464f 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -902,6 +902,16 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) return rc; } device = (struct dasd_device *) cqr->startdev; + if (((cqr->block && + test_bit(DASD_FLAG_LOCK_STOLEN, &cqr->block->base->flags)) || + test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) && + !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { + DBF_DEV_EVENT(DBF_DEBUG, device, "start_IO: return request %p " + "because of stolen lock", cqr); + cqr->status = DASD_CQR_ERROR; + cqr->intrc = -EPERM; + return -EPERM; + } if (cqr->retries < 0) { /* internal error 14 - start_IO run out of retries */ sprintf(errorstring, "14 %p", cqr); @@ -1115,16 +1125,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, } now = get_clock(); - - /* check for unsolicited interrupts */ cqr = (struct dasd_ccw_req *) intparm; - if (!cqr || ((scsw_cc(&irb->scsw) == 1) && - (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && - ((scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND) || - (scsw_stctl(&irb->scsw) == (SCSW_STCTL_STATUS_PEND | - SCSW_STCTL_ALERT_STATUS))))) { - if (cqr && cqr->status == DASD_CQR_IN_IO) - cqr->status = DASD_CQR_QUEUED; + /* check for conditions that should be handled immediately */ + if (!cqr || + !(scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && + scsw_cstat(&irb->scsw) == 0)) { if (cqr) memcpy(&cqr->irb, irb, sizeof(*irb)); device = dasd_device_from_cdev_locked(cdev); @@ -1135,17 +1140,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, dasd_put_device(device); return; } - device->discipline->dump_sense_dbf(device, irb, - "unsolicited"); - if ((device->features & DASD_FEATURE_ERPLOG)) - device->discipline->dump_sense(device, cqr, - irb); - dasd_device_clear_timer(device); - device->discipline->handle_unsolicited_interrupt(device, - irb); + device->discipline->dump_sense_dbf(device, irb, "int"); + if (device->features & DASD_FEATURE_ERPLOG) + device->discipline->dump_sense(device, cqr, irb); + device->discipline->check_for_device_change(device, cqr, irb); dasd_put_device(device); - return; } + if (!cqr) + return; device = (struct dasd_device *) cqr->startdev; if (!device || @@ -1185,13 +1187,6 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, struct dasd_ccw_req, devlist); } } else { /* error */ - memcpy(&cqr->irb, irb, sizeof(struct irb)); - /* log sense for every failed I/O to s390 debugfeature */ - dasd_log_sense_dbf(cqr, irb); - if (device->features & DASD_FEATURE_ERPLOG) { - dasd_log_sense(cqr, irb); - } - /* * If we don't want complex ERP for this request, then just * reset this and retry it in the fastpath @@ -1232,13 +1227,13 @@ enum uc_todo dasd_generic_uc_handler(struct ccw_device *cdev, struct irb *irb) goto out; if (test_bit(DASD_FLAG_OFFLINE, &device->flags) || device->state != device->target || - !device->discipline->handle_unsolicited_interrupt){ + !device->discipline->check_for_device_change){ dasd_put_device(device); goto out; } - - dasd_device_clear_timer(device); - device->discipline->handle_unsolicited_interrupt(device, irb); + if (device->discipline->dump_sense_dbf) + device->discipline->dump_sense_dbf(device, irb, "uc"); + device->discipline->check_for_device_change(device, NULL, irb); dasd_put_device(device); out: return UC_TODO_RETRY; @@ -1659,7 +1654,12 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) continue; if (cqr->status != DASD_CQR_FILLED) /* could be failed */ continue; - + if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) && + !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { + cqr->status = DASD_CQR_FAILED; + cqr->intrc = -EPERM; + continue; + } /* Non-temporary stop condition will trigger fail fast */ if (device->stopped & ~DASD_STOPPED_PENDING && test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && @@ -1667,7 +1667,6 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) cqr->status = DASD_CQR_FAILED; continue; } - /* Don't try to start requests if device is stopped */ if (interruptible) { rc = wait_event_interruptible( @@ -1752,13 +1751,18 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) int rc; device = cqr->startdev; + if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) && + !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { + cqr->status = DASD_CQR_FAILED; + cqr->intrc = -EPERM; + return -EIO; + } spin_lock_irq(get_ccwdev_lock(device->cdev)); rc = _dasd_term_running_cqr(device); if (rc) { spin_unlock_irq(get_ccwdev_lock(device->cdev)); return rc; } - cqr->callback = dasd_wakeup_cb; cqr->callback_data = DASD_SLEEPON_START_TAG; cqr->status = DASD_CQR_QUEUED; @@ -2062,6 +2066,13 @@ static void __dasd_block_start_head(struct dasd_block *block) list_for_each_entry(cqr, &block->ccw_queue, blocklist) { if (cqr->status != DASD_CQR_FILLED) continue; + if (test_bit(DASD_FLAG_LOCK_STOLEN, &block->base->flags) && + !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { + cqr->status = DASD_CQR_FAILED; + cqr->intrc = -EPERM; + dasd_schedule_block_bh(block); + continue; + } /* Non-temporary stop condition will trigger fail fast */ if (block->base->stopped & ~DASD_STOPPED_PENDING && test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 0001df8ad3e6..47fc88692494 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -1127,6 +1127,103 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store); +static ssize_t dasd_reservation_policy_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dasd_devmap *devmap; + int rc = 0; + + devmap = dasd_find_busid(dev_name(dev)); + if (IS_ERR(devmap)) { + rc = snprintf(buf, PAGE_SIZE, "ignore\n"); + } else { + spin_lock(&dasd_devmap_lock); + if (devmap->features & DASD_FEATURE_FAILONSLCK) + rc = snprintf(buf, PAGE_SIZE, "fail\n"); + else + rc = snprintf(buf, PAGE_SIZE, "ignore\n"); + spin_unlock(&dasd_devmap_lock); + } + return rc; +} + +static ssize_t dasd_reservation_policy_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dasd_devmap *devmap; + int rc; + + devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); + if (IS_ERR(devmap)) + return PTR_ERR(devmap); + rc = 0; + spin_lock(&dasd_devmap_lock); + if (sysfs_streq("ignore", buf)) + devmap->features &= ~DASD_FEATURE_FAILONSLCK; + else if (sysfs_streq("fail", buf)) + devmap->features |= DASD_FEATURE_FAILONSLCK; + else + rc = -EINVAL; + if (devmap->device) + devmap->device->features = devmap->features; + spin_unlock(&dasd_devmap_lock); + if (rc) + return rc; + else + return count; +} + +static DEVICE_ATTR(reservation_policy, 0644, + dasd_reservation_policy_show, dasd_reservation_policy_store); + +static ssize_t dasd_reservation_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dasd_device *device; + int rc = 0; + + device = dasd_device_from_cdev(to_ccwdev(dev)); + if (IS_ERR(device)) + return snprintf(buf, PAGE_SIZE, "none\n"); + + if (test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) + rc = snprintf(buf, PAGE_SIZE, "reserved\n"); + else if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) + rc = snprintf(buf, PAGE_SIZE, "lost\n"); + else + rc = snprintf(buf, PAGE_SIZE, "none\n"); + dasd_put_device(device); + return rc; +} + +static ssize_t dasd_reservation_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dasd_device *device; + int rc = 0; + + device = dasd_device_from_cdev(to_ccwdev(dev)); + if (IS_ERR(device)) + return -ENODEV; + if (sysfs_streq("reset", buf)) + clear_bit(DASD_FLAG_LOCK_STOLEN, &device->flags); + else + rc = -EINVAL; + dasd_put_device(device); + + if (rc) + return rc; + else + return count; +} + +static DEVICE_ATTR(last_known_reservation_state, 0644, + dasd_reservation_state_show, dasd_reservation_state_store); + static struct attribute * dasd_attrs[] = { &dev_attr_readonly.attr, &dev_attr_discipline.attr, @@ -1139,6 +1236,8 @@ static struct attribute * dasd_attrs[] = { &dev_attr_erplog.attr, &dev_attr_failfast.attr, &dev_attr_expires.attr, + &dev_attr_reservation_policy.attr, + &dev_attr_last_known_reservation_state.attr, NULL, }; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index a1ebf5722ae5..46eafce3a0a6 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -817,6 +817,7 @@ static int dasd_eckd_read_conf_immediately(struct dasd_device *device, dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buffer, lpm); clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); cqr->retries = 5; rc = dasd_sleep_on_immediatly(cqr); return rc; @@ -1947,9 +1948,9 @@ dasd_eckd_erp_postaction(struct dasd_ccw_req * cqr) return dasd_default_erp_postaction; } - -static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, - struct irb *irb) +static void dasd_eckd_check_for_device_change(struct dasd_device *device, + struct dasd_ccw_req *cqr, + struct irb *irb) { char mask; char *sense = NULL; @@ -1973,40 +1974,41 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, /* schedule worker to reload device */ dasd_reload_device(device); } - dasd_generic_handle_state_change(device); return; } - /* summary unit check */ sense = dasd_get_sense(irb); - if (sense && (sense[7] == 0x0D) && + if (!sense) + return; + + /* summary unit check */ + if ((sense[7] == 0x0D) && (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) { dasd_alias_handle_summary_unit_check(device, irb); return; } /* service information message SIM */ - if (sense && !(sense[27] & DASD_SENSE_BIT_0) && + if (!cqr && !(sense[27] & DASD_SENSE_BIT_0) && ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { dasd_3990_erp_handle_sim(device, sense); - dasd_schedule_device_bh(device); return; } - if ((scsw_cc(&irb->scsw) == 1) && !sense && - (scsw_fctl(&irb->scsw) == SCSW_FCTL_START_FUNC) && - (scsw_actl(&irb->scsw) == SCSW_ACTL_START_PEND) && - (scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND)) { - /* fake irb do nothing, they are handled elsewhere */ - dasd_schedule_device_bh(device); - return; + /* loss of device reservation is handled via base devices only + * as alias devices may be used with several bases + */ + if (device->block && (sense[7] == 0x3F) && + (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && + test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) { + if (device->features & DASD_FEATURE_FAILONSLCK) + set_bit(DASD_FLAG_LOCK_STOLEN, &device->flags); + clear_bit(DASD_FLAG_IS_RESERVED, &device->flags); + dev_err(&device->cdev->dev, + "The device reservation was lost\n"); } - - dasd_schedule_device_bh(device); - return; -}; - +} static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( struct dasd_device *startdev, @@ -2931,6 +2933,8 @@ dasd_eckd_release(struct dasd_device *device) cqr->status = DASD_CQR_FILLED; rc = dasd_sleep_on_immediatly(cqr); + if (!rc) + clear_bit(DASD_FLAG_IS_RESERVED, &device->flags); if (useglobal) mutex_unlock(&dasd_reserve_mutex); @@ -2984,6 +2988,8 @@ dasd_eckd_reserve(struct dasd_device *device) cqr->status = DASD_CQR_FILLED; rc = dasd_sleep_on_immediatly(cqr); + if (!rc) + set_bit(DASD_FLAG_IS_RESERVED, &device->flags); if (useglobal) mutex_unlock(&dasd_reserve_mutex); @@ -3036,6 +3042,8 @@ dasd_eckd_steal_lock(struct dasd_device *device) cqr->status = DASD_CQR_FILLED; rc = dasd_sleep_on_immediatly(cqr); + if (!rc) + set_bit(DASD_FLAG_IS_RESERVED, &device->flags); if (useglobal) mutex_unlock(&dasd_reserve_mutex); @@ -3088,6 +3096,7 @@ static int dasd_eckd_snid(struct dasd_device *device, cqr->memdev = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); cqr->retries = 5; cqr->expires = 10 * HZ; cqr->buildclk = get_clock(); @@ -3832,7 +3841,7 @@ static struct dasd_discipline dasd_eckd_discipline = { .format_device = dasd_eckd_format_device, .erp_action = dasd_eckd_erp_action, .erp_postaction = dasd_eckd_erp_postaction, - .handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt, + .check_for_device_change = dasd_eckd_check_for_device_change, .build_cp = dasd_eckd_build_alias_cp, .free_cp = dasd_eckd_free_alias_cp, .dump_sense = dasd_eckd_dump_sense, diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 83b4615a3b62..77f778b7b070 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -473,6 +473,7 @@ int dasd_eer_enable(struct dasd_device *device) cqr->retries = 255; cqr->expires = 10 * HZ; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_SNSS; diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 86bacda2c5f6..be89b3a893da 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -233,24 +233,16 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr) return NULL; } -static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device, - struct irb *irb) +static void dasd_fba_check_for_device_change(struct dasd_device *device, + struct dasd_ccw_req *cqr, + struct irb *irb) { char mask; /* first of all check for state change pending interrupt */ mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; - if ((irb->scsw.cmd.dstat & mask) == mask) { + if ((irb->scsw.cmd.dstat & mask) == mask) dasd_generic_handle_state_change(device); - return; - } - - /* check for unsolicited interrupts */ - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "unsolicited interrupt received"); - device->discipline->dump_sense_dbf(device, irb, "unsolicited"); - dasd_schedule_device_bh(device); - return; }; static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, @@ -605,7 +597,7 @@ static struct dasd_discipline dasd_fba_discipline = { .handle_terminated_request = dasd_fba_handle_terminated_request, .erp_action = dasd_fba_erp_action, .erp_postaction = dasd_fba_erp_postaction, - .handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt, + .check_for_device_change = dasd_fba_check_for_device_change, .build_cp = dasd_fba_build_cp, .free_cp = dasd_fba_free_cp, .dump_sense = dasd_fba_dump_sense, diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index ba038ef57606..df9f6999411d 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -232,6 +232,10 @@ struct dasd_ccw_req { #define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ #define DASD_CQR_FLAGS_FAILFAST 1 /* FAILFAST */ #define DASD_CQR_VERIFY_PATH 2 /* path verification request */ +#define DASD_CQR_ALLOW_SLOCK 3 /* Try this request even when lock was + * stolen. Should not be combined with + * DASD_CQR_FLAGS_USE_ERP + */ /* Signature for error recovery functions. */ typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); @@ -334,9 +338,9 @@ struct dasd_discipline { void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *, struct irb *); void (*dump_sense_dbf) (struct dasd_device *, struct irb *, char *); - - void (*handle_unsolicited_interrupt) (struct dasd_device *, - struct irb *); + void (*check_for_device_change) (struct dasd_device *, + struct dasd_ccw_req *, + struct irb *); /* i/o control functions. */ int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); @@ -473,6 +477,9 @@ struct dasd_block { * confuse this with the user specified * read-only feature. */ +#define DASD_FLAG_IS_RESERVED 7 /* The device is reserved */ +#define DASD_FLAG_LOCK_STOLEN 8 /* The device lock was stolen */ + void dasd_put_device_wake(struct dasd_device *); -- cgit v1.2.3 From 6f272b9cec285a9610a2acf101f694bc58bed37e Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 5 Jan 2011 12:48:05 +0100 Subject: [S390] dasd: Prevent deadlock during suspend/resume. The freeze callback may set a stop bit so that a worker thread could not start I/O. The discipline specific freeze function waits for the worker to be completed. Set the stop_bit after the discipline specific freeze function has returned and no worker is running. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index f16afe74464f..82d9ce36bd0b 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2769,6 +2769,10 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev) if (IS_ERR(device)) return PTR_ERR(device); + + if (device->discipline->freeze) + rc = device->discipline->freeze(device); + /* disallow new I/O */ dasd_device_set_stop_bits(device, DASD_STOPPED_PM); /* clear active requests */ @@ -2805,9 +2809,6 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev) list_splice_tail(&freeze_queue, &device->ccw_queue); spin_unlock_irq(get_ccwdev_lock(cdev)); - if (device->discipline->freeze) - rc = device->discipline->freeze(device); - dasd_put_device(device); return rc; } -- cgit v1.2.3 From e4dbb0f2b5dd6a836d0e5c60aa5f573e0bbcf76a Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 5 Jan 2011 12:48:06 +0100 Subject: [S390] dasd: Add support for raw ECKD access. Normal I/O operations through the DASD device driver give only access to the data fields of an ECKD device even for track based I/O. This patch extends the DASD device driver to give access to whole ECKD tracks including count, key and data fields. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/dasd.h | 2 + drivers/s390/block/dasd.c | 23 ++++- drivers/s390/block/dasd_devmap.c | 55 ++++++++++- drivers/s390/block/dasd_eckd.c | 194 ++++++++++++++++++++++++++++++++++++++- drivers/s390/block/dasd_eckd.h | 2 + 5 files changed, 268 insertions(+), 8 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h index 47fcdada5d25..0be28efe5b66 100644 --- a/arch/s390/include/asm/dasd.h +++ b/arch/s390/include/asm/dasd.h @@ -73,6 +73,7 @@ typedef struct dasd_information2_t { * 0x02: use diag discipline (diag) * 0x04: set the device initially online (internal use only) * 0x08: enable ERP related logging + * 0x20: give access to raw eckd data */ #define DASD_FEATURE_DEFAULT 0x00 #define DASD_FEATURE_READONLY 0x01 @@ -81,6 +82,7 @@ typedef struct dasd_information2_t { #define DASD_FEATURE_ERPLOG 0x08 #define DASD_FEATURE_FAILFAST 0x10 #define DASD_FEATURE_FAILONSLCK 0x20 +#define DASD_FEATURE_USERAW 0x40 #define DASD_PARTN_BITS 2 diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 82d9ce36bd0b..4e266f43332d 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -369,6 +369,11 @@ dasd_state_ready_to_online(struct dasd_device * device) device->state = DASD_STATE_ONLINE; if (device->block) { dasd_schedule_block_bh(device->block); + if ((device->features & DASD_FEATURE_USERAW)) { + disk = device->block->gdp; + kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); + return 0; + } disk = device->block->bdev->bd_disk; disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); while ((part = disk_part_iter_next(&piter))) @@ -394,7 +399,7 @@ static int dasd_state_online_to_ready(struct dasd_device *device) return rc; } device->state = DASD_STATE_READY; - if (device->block) { + if (device->block && !(device->features & DASD_FEATURE_USERAW)) { disk = device->block->bdev->bd_disk; disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); while ((part = disk_part_iter_next(&piter))) @@ -2258,8 +2263,20 @@ static void dasd_setup_queue(struct dasd_block *block) { int max; - blk_queue_logical_block_size(block->request_queue, block->bp_block); - max = block->base->discipline->max_blocks << block->s2b_shift; + if (block->base->features & DASD_FEATURE_USERAW) { + /* + * the max_blocks value for raw_track access is 256 + * it is higher than the native ECKD value because we + * only need one ccw per track + * so the max_hw_sectors are + * 2048 x 512B = 1024kB = 16 tracks + */ + max = 2048; + } else { + max = block->base->discipline->max_blocks << block->s2b_shift; + } + blk_queue_logical_block_size(block->request_queue, + block->bp_block); blk_queue_max_hw_sectors(block->request_queue, max); blk_queue_max_segments(block->request_queue, -1L); /* with page sized segments we can translate each segement into diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 47fc88692494..cb6a67bc89ff 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -208,6 +208,8 @@ dasd_feature_list(char *str, char **endp) features |= DASD_FEATURE_READONLY; else if (len == 4 && !strncmp(str, "diag", 4)) features |= DASD_FEATURE_USEDIAG; + else if (len == 3 && !strncmp(str, "raw", 3)) + features |= DASD_FEATURE_USERAW; else if (len == 6 && !strncmp(str, "erplog", 6)) features |= DASD_FEATURE_ERPLOG; else if (len == 8 && !strncmp(str, "failfast", 8)) @@ -857,7 +859,7 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, spin_lock(&dasd_devmap_lock); /* Changing diag discipline flag is only allowed in offline state. */ rc = count; - if (!devmap->device) { + if (!devmap->device && !(devmap->features & DASD_FEATURE_USERAW)) { if (val) devmap->features |= DASD_FEATURE_USEDIAG; else @@ -870,6 +872,56 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store); +/* + * use_raw controls whether the driver should give access to raw eckd data or + * operate in standard mode + */ +static ssize_t +dasd_use_raw_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dasd_devmap *devmap; + int use_raw; + + devmap = dasd_find_busid(dev_name(dev)); + if (!IS_ERR(devmap)) + use_raw = (devmap->features & DASD_FEATURE_USERAW) != 0; + else + use_raw = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USERAW) != 0; + return sprintf(buf, use_raw ? "1\n" : "0\n"); +} + +static ssize_t +dasd_use_raw_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dasd_devmap *devmap; + ssize_t rc; + unsigned long val; + + devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); + if (IS_ERR(devmap)) + return PTR_ERR(devmap); + + if ((strict_strtoul(buf, 10, &val) != 0) || val > 1) + return -EINVAL; + + spin_lock(&dasd_devmap_lock); + /* Changing diag discipline flag is only allowed in offline state. */ + rc = count; + if (!devmap->device && !(devmap->features & DASD_FEATURE_USEDIAG)) { + if (val) + devmap->features |= DASD_FEATURE_USERAW; + else + devmap->features &= ~DASD_FEATURE_USERAW; + } else + rc = -EPERM; + spin_unlock(&dasd_devmap_lock); + return rc; +} + +static DEVICE_ATTR(raw_track_access, 0644, dasd_use_raw_show, + dasd_use_raw_store); + static ssize_t dasd_discipline_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1232,6 +1284,7 @@ static struct attribute * dasd_attrs[] = { &dev_attr_vendor.attr, &dev_attr_uid.attr, &dev_attr_use_diag.attr, + &dev_attr_raw_track_access.attr, &dev_attr_eer_enabled.attr, &dev_attr_erplog.attr, &dev_attr_failfast.attr, diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 46eafce3a0a6..318672d05563 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -54,6 +54,15 @@ #define ECKD_F7(i) (i->factor7) #define ECKD_F8(i) (i->factor8) +/* + * raw track access always map to 64k in memory + * so it maps to 16 blocks of 4k per track + */ +#define DASD_RAW_BLOCK_PER_TRACK 16 +#define DASD_RAW_BLOCKSIZE 4096 +/* 64k are 128 x 512 byte sectors */ +#define DASD_RAW_SECTORS_PER_TRACK 128 + MODULE_LICENSE("GPL"); static struct dasd_discipline dasd_eckd_discipline; @@ -385,6 +394,23 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk, data->length = reclen; data->operation.operation = 0x03; break; + case DASD_ECKD_CCW_WRITE_FULL_TRACK: + data->operation.orientation = 0x0; + data->operation.operation = 0x3F; + data->extended_operation = 0x11; + data->length = 0; + data->extended_parameter_length = 0x02; + if (data->count > 8) { + data->extended_parameter[0] = 0xFF; + data->extended_parameter[1] = 0xFF; + data->extended_parameter[1] <<= (16 - count); + } else { + data->extended_parameter[0] = 0xFF; + data->extended_parameter[0] <<= (8 - count); + data->extended_parameter[1] = 0x00; + } + data->sector = 0xFF; + break; case DASD_ECKD_CCW_WRITE_TRACK_DATA: data->auxiliary.length_valid = 0x1; data->length = reclen; /* not tlf, as one might think */ @@ -408,6 +434,12 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk, case DASD_ECKD_CCW_READ_COUNT: data->operation.operation = 0x06; break; + case DASD_ECKD_CCW_READ_TRACK: + data->operation.orientation = 0x1; + data->operation.operation = 0x0C; + data->extended_parameter_length = 0; + data->sector = 0xFF; + break; case DASD_ECKD_CCW_READ_TRACK_DATA: data->auxiliary.length_valid = 0x1; data->length = tlf; @@ -451,10 +483,16 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, ccw->cmd_code = DASD_ECKD_CCW_PFX; ccw->flags = 0; - ccw->count = sizeof(*pfxdata); - ccw->cda = (__u32) __pa(pfxdata); + if (cmd == DASD_ECKD_CCW_WRITE_FULL_TRACK) { + ccw->count = sizeof(*pfxdata) + 2; + ccw->cda = (__u32) __pa(pfxdata); + memset(pfxdata, 0, sizeof(*pfxdata) + 2); + } else { + ccw->count = sizeof(*pfxdata); + ccw->cda = (__u32) __pa(pfxdata); + memset(pfxdata, 0, sizeof(*pfxdata)); + } - memset(pfxdata, 0, sizeof(*pfxdata)); /* prefix data */ if (format > 1) { DBF_DEV_EVENT(DBF_ERR, basedev, @@ -488,6 +526,7 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, dedata->mask.perm = 0x1; dedata->attributes.operation = basepriv->attrib.operation; break; + case DASD_ECKD_CCW_READ_TRACK: case DASD_ECKD_CCW_READ_TRACK_DATA: dedata->mask.perm = 0x1; dedata->attributes.operation = basepriv->attrib.operation; @@ -514,6 +553,11 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, dedata->attributes.operation = DASD_BYPASS_CACHE; rc = check_XRC_on_prefix(pfxdata, basedev); break; + case DASD_ECKD_CCW_WRITE_FULL_TRACK: + dedata->mask.perm = 0x03; + dedata->attributes.operation = basepriv->attrib.operation; + dedata->blk_size = 0; + break; case DASD_ECKD_CCW_WRITE_TRACK_DATA: dedata->mask.perm = 0x02; dedata->attributes.operation = basepriv->attrib.operation; @@ -1607,6 +1651,13 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) dasd_sfree_request(init_cqr, device); } + if (device->features & DASD_FEATURE_USERAW) { + block->bp_block = DASD_RAW_BLOCKSIZE; + blk_per_trk = DASD_RAW_BLOCK_PER_TRACK; + block->s2b_shift = 3; + goto raw; + } + if (status == INIT_CQR_UNFORMATTED) { dev_warn(&device->cdev->dev, "The DASD is not formatted\n"); return -EMEDIUMTYPE; @@ -1644,6 +1695,7 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) dev_warn(&device->cdev->dev, "Track 0 has no records following the VTOC\n"); } + if (count_area != NULL && count_area->kl == 0) { /* we found notthing violating our disk layout */ if (dasd_check_blocksize(count_area->dl) == 0) @@ -1659,6 +1711,8 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) block->s2b_shift++; blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); + +raw: block->blocks = (private->real_cyl * private->rdc_data.trk_per_cyl * blk_per_trk); @@ -2741,6 +2795,135 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, return cqr; } +static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, + struct dasd_block *block, + struct request *req) +{ + struct dasd_eckd_private *private; + unsigned long *idaws; + struct dasd_device *basedev; + struct dasd_ccw_req *cqr; + struct ccw1 *ccw; + struct req_iterator iter; + struct bio_vec *bv; + char *dst; + unsigned char cmd; + unsigned int trkcount; + unsigned int seg_len, len_to_track_end; + unsigned int first_offs; + unsigned int cidaw, cplength, datasize; + sector_t first_trk, last_trk; + unsigned int pfx_datasize; + + /* + * raw track access needs to be mutiple of 64k and on 64k boundary + */ + if ((blk_rq_pos(req) % DASD_RAW_SECTORS_PER_TRACK) != 0) { + cqr = ERR_PTR(-EINVAL); + goto out; + } + if (((blk_rq_pos(req) + blk_rq_sectors(req)) % + DASD_RAW_SECTORS_PER_TRACK) != 0) { + cqr = ERR_PTR(-EINVAL); + goto out; + } + + first_trk = blk_rq_pos(req) / DASD_RAW_SECTORS_PER_TRACK; + last_trk = (blk_rq_pos(req) + blk_rq_sectors(req) - 1) / + DASD_RAW_SECTORS_PER_TRACK; + trkcount = last_trk - first_trk + 1; + first_offs = 0; + basedev = block->base; + private = (struct dasd_eckd_private *) basedev->private; + + if (rq_data_dir(req) == READ) + cmd = DASD_ECKD_CCW_READ_TRACK; + else if (rq_data_dir(req) == WRITE) + cmd = DASD_ECKD_CCW_WRITE_FULL_TRACK; + else { + cqr = ERR_PTR(-EINVAL); + goto out; + } + + /* + * Raw track based I/O needs IDAWs for each page, + * and not just for 64 bit addresses. + */ + cidaw = trkcount * DASD_RAW_BLOCK_PER_TRACK; + + /* 1x prefix + one read/write ccw per track */ + cplength = 1 + trkcount; + + /* + * struct PFX_eckd_data has up to 2 byte as extended parameter + * this is needed for write full track and has to be mentioned + * seperately + * add 8 instead of 2 to keep 8 byte boundary + */ + pfx_datasize = sizeof(struct PFX_eckd_data) + 8; + + datasize = pfx_datasize + cidaw * sizeof(unsigned long long); + + /* Allocate the ccw request. */ + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, + datasize, startdev); + if (IS_ERR(cqr)) + goto out; + ccw = cqr->cpaddr; + + if (prefix_LRE(ccw++, cqr->data, first_trk, last_trk, cmd, + basedev, startdev, 1 /* format */, first_offs + 1, + trkcount, 0, 0) == -EAGAIN) { + /* Clock not in sync and XRC is enabled. + * Try again later. + */ + dasd_sfree_request(cqr, startdev); + cqr = ERR_PTR(-EAGAIN); + goto out; + } + + idaws = (unsigned long *)(cqr->data + pfx_datasize); + + len_to_track_end = 0; + + rq_for_each_segment(bv, req, iter) { + dst = page_address(bv->bv_page) + bv->bv_offset; + seg_len = bv->bv_len; + if (!len_to_track_end) { + ccw[-1].flags |= CCW_FLAG_CC; + ccw->cmd_code = cmd; + /* maximum 3390 track size */ + ccw->count = 57326; + /* 64k map to one track */ + len_to_track_end = 65536; + ccw->cda = (__u32)(addr_t)idaws; + ccw->flags |= CCW_FLAG_IDA; + ccw->flags |= CCW_FLAG_SLI; + ccw++; + } + len_to_track_end -= seg_len; + idaws = idal_create_words(idaws, dst, seg_len); + } + + if (blk_noretry_request(req) || + block->base->features & DASD_FEATURE_FAILFAST) + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->startdev = startdev; + cqr->memdev = startdev; + cqr->block = block; + cqr->expires = startdev->default_expires * HZ; + cqr->lpm = startdev->path_data.ppm; + cqr->retries = 256; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + + if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) + cqr = NULL; +out: + return cqr; +} + + static int dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) { @@ -2845,7 +3028,10 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base, spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags); private->count++; - cqr = dasd_eckd_build_cp(startdev, block, req); + if ((base->features & DASD_FEATURE_USERAW)) + cqr = dasd_raw_build_cp(startdev, block, req); + else + cqr = dasd_eckd_build_cp(startdev, block, req); if (IS_ERR(cqr)) private->count--; spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags); diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 5051f374cbcb..4a688a873a77 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -37,11 +37,13 @@ #define DASD_ECKD_CCW_WRITE_KD_MT 0x8d #define DASD_ECKD_CCW_READ_KD_MT 0x8e #define DASD_ECKD_CCW_RELEASE 0x94 +#define DASD_ECKD_CCW_WRITE_FULL_TRACK 0x95 #define DASD_ECKD_CCW_READ_CKD_MT 0x9e #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d #define DASD_ECKD_CCW_WRITE_TRACK_DATA 0xA5 #define DASD_ECKD_CCW_READ_TRACK_DATA 0xA6 #define DASD_ECKD_CCW_RESERVE 0xB4 +#define DASD_ECKD_CCW_READ_TRACK 0xDE #define DASD_ECKD_CCW_PFX 0xE7 #define DASD_ECKD_CCW_PFX_READ 0xEA #define DASD_ECKD_CCW_RSCK 0xF9 -- cgit v1.2.3 From 09a8e7adcf960bd6a7204f3f3b377a89ce22efbf Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 5 Jan 2011 12:48:07 +0100 Subject: [S390] dasd: Correct retry counter for terminated I/O. In case the DASD driver needs to term a running I/O the retry counter is decreased twice. Remove the unnecessary retry counter decrease in das_term_IO. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4e266f43332d..794bfd962266 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -855,7 +855,6 @@ int dasd_term_IO(struct dasd_ccw_req *cqr) rc = ccw_device_clear(device->cdev, (long) cqr); switch (rc) { case 0: /* termination successful */ - cqr->retries--; cqr->status = DASD_CQR_CLEAR_PENDING; cqr->stopclk = get_clock(); cqr->starttime = 0; -- cgit v1.2.3 From c03017544e3b2e60aa3c8ae451fac01595f1bf11 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Wed, 5 Jan 2011 12:48:13 +0100 Subject: [S390] cio: fix ccwgroup unregistration race condition A race condition exists in the ccwgroup device unregistration code which can cause a kernel panic due to a use-after-free bug. This race condition might be triggered when all ccw devices associated with a ccwgroup device are removed at the same time (e.g. because the corresponding channel path becomes no longer available). Fix this race condition by clearing the references from the associated ccw devices to the ccw group device during unregistration of the ccw group device. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/ccwgroup.c | 78 +++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 38 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 97b25d68e3e7..2864581d8ecb 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -66,6 +66,27 @@ __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) } +/* + * Remove references from ccw devices to ccw group device and from + * ccw group device to ccw devices. + */ +static void __ccwgroup_remove_cdev_refs(struct ccwgroup_device *gdev) +{ + struct ccw_device *cdev; + int i; + + for (i = 0; i < gdev->count; i++) { + cdev = gdev->cdev[i]; + if (!cdev) + continue; + spin_lock_irq(cdev->ccwlock); + dev_set_drvdata(&cdev->dev, NULL); + spin_unlock_irq(cdev->ccwlock); + gdev->cdev[i] = NULL; + put_device(&cdev->dev); + } +} + /* * Provide an 'ungroup' attribute so the user can remove group devices no * longer needed or accidentially created. Saves memory :) @@ -78,6 +99,7 @@ static void ccwgroup_ungroup_callback(struct device *dev) if (device_is_registered(&gdev->dev)) { __ccwgroup_remove_symlinks(gdev); device_unregister(dev); + __ccwgroup_remove_cdev_refs(gdev); } mutex_unlock(&gdev->reg_mutex); } @@ -116,21 +138,7 @@ static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store); static void ccwgroup_release (struct device *dev) { - struct ccwgroup_device *gdev; - int i; - - gdev = to_ccwgroupdev(dev); - - for (i = 0; i < gdev->count; i++) { - if (gdev->cdev[i]) { - spin_lock_irq(gdev->cdev[i]->ccwlock); - if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) - dev_set_drvdata(&gdev->cdev[i]->dev, NULL); - spin_unlock_irq(gdev->cdev[i]->ccwlock); - put_device(&gdev->cdev[i]->dev); - } - } - kfree(gdev); + kfree(to_ccwgroupdev(dev)); } static int @@ -639,6 +647,7 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) mutex_lock(&gdev->reg_mutex); __ccwgroup_remove_symlinks(gdev); device_unregister(dev); + __ccwgroup_remove_cdev_refs(gdev); mutex_unlock(&gdev->reg_mutex); put_device(dev); } @@ -660,25 +669,6 @@ int ccwgroup_probe_ccwdev(struct ccw_device *cdev) return 0; } -static struct ccwgroup_device * -__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) -{ - struct ccwgroup_device *gdev; - - gdev = dev_get_drvdata(&cdev->dev); - if (gdev) { - if (get_device(&gdev->dev)) { - mutex_lock(&gdev->reg_mutex); - if (device_is_registered(&gdev->dev)) - return gdev; - mutex_unlock(&gdev->reg_mutex); - put_device(&gdev->dev); - } - return NULL; - } - return NULL; -} - /** * ccwgroup_remove_ccwdev() - remove function for slave devices * @cdev: ccw device to be removed @@ -694,13 +684,25 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev) /* Ignore offlining errors, device is gone anyway. */ ccw_device_set_offline(cdev); /* If one of its devices is gone, the whole group is done for. */ - gdev = __ccwgroup_get_gdev_by_cdev(cdev); - if (gdev) { + spin_lock_irq(cdev->ccwlock); + gdev = dev_get_drvdata(&cdev->dev); + if (!gdev) { + spin_unlock_irq(cdev->ccwlock); + return; + } + /* Get ccwgroup device reference for local processing. */ + get_device(&gdev->dev); + spin_unlock_irq(cdev->ccwlock); + /* Unregister group device. */ + mutex_lock(&gdev->reg_mutex); + if (device_is_registered(&gdev->dev)) { __ccwgroup_remove_symlinks(gdev); device_unregister(&gdev->dev); - mutex_unlock(&gdev->reg_mutex); - put_device(&gdev->dev); + __ccwgroup_remove_cdev_refs(gdev); } + mutex_unlock(&gdev->reg_mutex); + /* Release ccwgroup device reference for local processing. */ + put_device(&gdev->dev); } MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 8e1023016cf17152972b98bce6c144834a4916d5 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 5 Jan 2011 12:48:18 +0100 Subject: [S390] prevent unneccesary loops_per_jiffy recalculation When the seqfile /proc/cpuinfo gets accesses for each possible cpu loops_per_jiffy gets recalculated. However its value is only needed on first access. In addition loops_per_jiffy should be recalculated when the machine reports a capability change. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/processor.c | 2 +- drivers/s390/char/sclp_config.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 753623bde8ec..311e9d712888 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -46,8 +46,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) unsigned long n = (unsigned long) v - 1; int i; - s390_adjust_jiffies(); if (!n) { + s390_adjust_jiffies(); seq_printf(m, "vendor_id : IBM/S390\n" "# processors : %i\n" "bogomips per cpu: %lu.%02lu\n", diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index b497afe061cc..16e232a99fb7 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -33,6 +33,7 @@ static void sclp_cpu_capability_notify(struct work_struct *work) int cpu; struct sys_device *sysdev; + s390_adjust_jiffies(); pr_warning("cpu capability changed.\n"); get_online_cpus(); for_each_online_cpu(cpu) { -- cgit v1.2.3