diff options
author | Eugene Crosser <Eugene.Crosser@ru.ibm.com> | 2014-01-14 09:54:12 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-01-15 17:48:01 -0500 |
commit | 59b55a4df24e2f105c87721bec3e6c80c3d7b20b (patch) | |
tree | 9dbffbe89719c0ec6bfa9273b73f1bf5e1a6a07b /drivers/s390 | |
parent | b4d72c08b358fc5b259fad0f4971112d949efd1c (diff) |
s390/qdio: bridgeport support - CHSC part
Introduce function for the "Perform network-subchannel operation"
CHSC command with operation code "bridgeport information",
and bit definitions for "characteristics" pertaning to this command.
Signed-off-by: Eugene Crosser <eugene.crosser@ru.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Reviewed-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/chsc.c | 33 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 51 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 91 |
3 files changed, 174 insertions, 1 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 13299f902676..d24b3672908d 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -55,6 +55,7 @@ int chsc_error_from_response(int response) | |||
55 | case 0x0004: | 55 | case 0x0004: |
56 | return -EOPNOTSUPP; | 56 | return -EOPNOTSUPP; |
57 | case 0x000b: | 57 | case 0x000b: |
58 | case 0x0107: /* "Channel busy" for the op 0x003d */ | ||
58 | return -EBUSY; | 59 | return -EBUSY; |
59 | case 0x0100: | 60 | case 0x0100: |
60 | case 0x0102: | 61 | case 0x0102: |
@@ -1234,3 +1235,35 @@ out: | |||
1234 | return ret; | 1235 | return ret; |
1235 | } | 1236 | } |
1236 | EXPORT_SYMBOL_GPL(chsc_scm_info); | 1237 | EXPORT_SYMBOL_GPL(chsc_scm_info); |
1238 | |||
1239 | /** | ||
1240 | * chsc_pnso_brinfo() - Perform Network-Subchannel Operation, Bridge Info. | ||
1241 | * @schid: id of the subchannel on which PNSO is performed | ||
1242 | * @brinfo_area: request and response block for the operation | ||
1243 | * @resume_token: resume token for multiblock response | ||
1244 | * @cnc: Boolean change-notification control | ||
1245 | * | ||
1246 | * brinfo_area must be allocated by the caller with get_zeroed_page(GFP_KERNEL) | ||
1247 | * | ||
1248 | * Returns 0 on success. | ||
1249 | */ | ||
1250 | int chsc_pnso_brinfo(struct subchannel_id schid, | ||
1251 | struct chsc_pnso_area *brinfo_area, | ||
1252 | struct chsc_brinfo_resume_token resume_token, | ||
1253 | int cnc) | ||
1254 | { | ||
1255 | memset(brinfo_area, 0, sizeof(*brinfo_area)); | ||
1256 | brinfo_area->request.length = 0x0030; | ||
1257 | brinfo_area->request.code = 0x003d; /* network-subchannel operation */ | ||
1258 | brinfo_area->m = schid.m; | ||
1259 | brinfo_area->ssid = schid.ssid; | ||
1260 | brinfo_area->sch = schid.sch_no; | ||
1261 | brinfo_area->cssid = schid.cssid; | ||
1262 | brinfo_area->oc = 0; /* Store-network-bridging-information list */ | ||
1263 | brinfo_area->resume_token = resume_token; | ||
1264 | brinfo_area->n = (cnc != 0); | ||
1265 | if (chsc(brinfo_area)) | ||
1266 | return -EIO; | ||
1267 | return chsc_error_from_response(brinfo_area->response.code); | ||
1268 | } | ||
1269 | EXPORT_SYMBOL_GPL(chsc_pnso_brinfo); | ||
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 23d072e70eb2..7e53a9c8b0b9 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
@@ -61,7 +61,9 @@ struct css_chsc_char { | |||
61 | u32 : 20; | 61 | u32 : 20; |
62 | u32 scssc : 1; /* bit 107 */ | 62 | u32 scssc : 1; /* bit 107 */ |
63 | u32 scsscf : 1; /* bit 108 */ | 63 | u32 scsscf : 1; /* bit 108 */ |
64 | u32 : 19; | 64 | u32:7; |
65 | u32 pnso:1; /* bit 116 */ | ||
66 | u32:11; | ||
65 | }__attribute__((packed)); | 67 | }__attribute__((packed)); |
66 | 68 | ||
67 | extern struct css_chsc_char css_chsc_characteristics; | 69 | extern struct css_chsc_char css_chsc_characteristics; |
@@ -188,6 +190,53 @@ struct chsc_scm_info { | |||
188 | 190 | ||
189 | int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token); | 191 | int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token); |
190 | 192 | ||
193 | struct chsc_brinfo_resume_token { | ||
194 | u64 t1; | ||
195 | u64 t2; | ||
196 | } __packed; | ||
197 | |||
198 | struct chsc_brinfo_naihdr { | ||
199 | struct chsc_brinfo_resume_token resume_token; | ||
200 | u32:32; | ||
201 | u32 instance; | ||
202 | u32:24; | ||
203 | u8 naids; | ||
204 | u32 reserved[3]; | ||
205 | } __packed; | ||
206 | |||
207 | struct chsc_pnso_area { | ||
208 | struct chsc_header request; | ||
209 | u8:2; | ||
210 | u8 m:1; | ||
211 | u8:5; | ||
212 | u8:2; | ||
213 | u8 ssid:2; | ||
214 | u8 fmt:4; | ||
215 | u16 sch; | ||
216 | u8:8; | ||
217 | u8 cssid; | ||
218 | u16:16; | ||
219 | u8 oc; | ||
220 | u32:24; | ||
221 | struct chsc_brinfo_resume_token resume_token; | ||
222 | u32 n:1; | ||
223 | u32:31; | ||
224 | u32 reserved[3]; | ||
225 | struct chsc_header response; | ||
226 | u32:32; | ||
227 | struct chsc_brinfo_naihdr naihdr; | ||
228 | union { | ||
229 | struct qdio_brinfo_entry_l3_ipv6 l3_ipv6[0]; | ||
230 | struct qdio_brinfo_entry_l3_ipv4 l3_ipv4[0]; | ||
231 | struct qdio_brinfo_entry_l2 l2[0]; | ||
232 | } entries; | ||
233 | } __packed; | ||
234 | |||
235 | int chsc_pnso_brinfo(struct subchannel_id schid, | ||
236 | struct chsc_pnso_area *brinfo_area, | ||
237 | struct chsc_brinfo_resume_token resume_token, | ||
238 | int cnc); | ||
239 | |||
191 | #ifdef CONFIG_SCM_BUS | 240 | #ifdef CONFIG_SCM_BUS |
192 | int scm_update_information(void); | 241 | int scm_update_information(void); |
193 | int scm_process_availability_information(void); | 242 | int scm_process_availability_information(void); |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 3e602e8affa7..5f99af4305fc 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -1752,6 +1752,97 @@ int qdio_stop_irq(struct ccw_device *cdev, int nr) | |||
1752 | } | 1752 | } |
1753 | EXPORT_SYMBOL(qdio_stop_irq); | 1753 | EXPORT_SYMBOL(qdio_stop_irq); |
1754 | 1754 | ||
1755 | /** | ||
1756 | * qdio_pnso_brinfo() - perform network subchannel op #0 - bridge info. | ||
1757 | * @schid: Subchannel ID. | ||
1758 | * @cnc: Boolean Change-Notification Control | ||
1759 | * @response: Response code will be stored at this address | ||
1760 | * @cb: Callback function will be executed for each element | ||
1761 | * of the address list | ||
1762 | * @priv: Pointer passed from the caller to qdio_pnso_brinfo() | ||
1763 | * @type: Type of the address entry passed to the callback | ||
1764 | * @entry: Entry containg the address of the specified type | ||
1765 | * @priv: Pointer to pass to the callback function. | ||
1766 | * | ||
1767 | * Performs "Store-network-bridging-information list" operation and calls | ||
1768 | * the callback function for every entry in the list. If "change- | ||
1769 | * notification-control" is set, further changes in the address list | ||
1770 | * will be reported via the IPA command. | ||
1771 | */ | ||
1772 | int qdio_pnso_brinfo(struct subchannel_id schid, | ||
1773 | int cnc, u16 *response, | ||
1774 | void (*cb)(void *priv, enum qdio_brinfo_entry_type type, | ||
1775 | void *entry), | ||
1776 | void *priv) | ||
1777 | { | ||
1778 | struct chsc_pnso_area *rr; | ||
1779 | int rc; | ||
1780 | u32 prev_instance = 0; | ||
1781 | int isfirstblock = 1; | ||
1782 | int i, size, elems; | ||
1783 | |||
1784 | rr = (struct chsc_pnso_area *)get_zeroed_page(GFP_KERNEL); | ||
1785 | if (rr == NULL) | ||
1786 | return -ENOMEM; | ||
1787 | do { | ||
1788 | /* on the first iteration, naihdr.resume_token will be zero */ | ||
1789 | rc = chsc_pnso_brinfo(schid, rr, rr->naihdr.resume_token, cnc); | ||
1790 | if (rc != 0 && rc != -EBUSY) | ||
1791 | goto out; | ||
1792 | if (rr->response.code != 1) { | ||
1793 | rc = -EIO; | ||
1794 | continue; | ||
1795 | } else | ||
1796 | rc = 0; | ||
1797 | |||
1798 | if (cb == NULL) | ||
1799 | continue; | ||
1800 | |||
1801 | size = rr->naihdr.naids; | ||
1802 | elems = (rr->response.length - | ||
1803 | sizeof(struct chsc_header) - | ||
1804 | sizeof(struct chsc_brinfo_naihdr)) / | ||
1805 | size; | ||
1806 | |||
1807 | if (!isfirstblock && (rr->naihdr.instance != prev_instance)) { | ||
1808 | /* Inform the caller that they need to scrap */ | ||
1809 | /* the data that was already reported via cb */ | ||
1810 | rc = -EAGAIN; | ||
1811 | break; | ||
1812 | } | ||
1813 | isfirstblock = 0; | ||
1814 | prev_instance = rr->naihdr.instance; | ||
1815 | for (i = 0; i < elems; i++) | ||
1816 | switch (size) { | ||
1817 | case sizeof(struct qdio_brinfo_entry_l3_ipv6): | ||
1818 | (*cb)(priv, l3_ipv6_addr, | ||
1819 | &rr->entries.l3_ipv6[i]); | ||
1820 | break; | ||
1821 | case sizeof(struct qdio_brinfo_entry_l3_ipv4): | ||
1822 | (*cb)(priv, l3_ipv4_addr, | ||
1823 | &rr->entries.l3_ipv4[i]); | ||
1824 | break; | ||
1825 | case sizeof(struct qdio_brinfo_entry_l2): | ||
1826 | (*cb)(priv, l2_addr_lnid, | ||
1827 | &rr->entries.l2[i]); | ||
1828 | break; | ||
1829 | default: | ||
1830 | WARN_ON_ONCE(1); | ||
1831 | rc = -EIO; | ||
1832 | goto out; | ||
1833 | } | ||
1834 | } while (rr->response.code == 0x0107 || /* channel busy */ | ||
1835 | (rr->response.code == 1 && /* list stored */ | ||
1836 | /* resume token is non-zero => list incomplete */ | ||
1837 | (rr->naihdr.resume_token.t1 || rr->naihdr.resume_token.t2))); | ||
1838 | (*response) = rr->response.code; | ||
1839 | |||
1840 | out: | ||
1841 | free_page((unsigned long)rr); | ||
1842 | return rc; | ||
1843 | } | ||
1844 | EXPORT_SYMBOL_GPL(qdio_pnso_brinfo); | ||
1845 | |||
1755 | static int __init init_QDIO(void) | 1846 | static int __init init_QDIO(void) |
1756 | { | 1847 | { |
1757 | int rc; | 1848 | int rc; |