aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorEugene Crosser <Eugene.Crosser@ru.ibm.com>2014-01-14 09:54:12 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-15 17:48:01 -0500
commit59b55a4df24e2f105c87721bec3e6c80c3d7b20b (patch)
tree9dbffbe89719c0ec6bfa9273b73f1bf5e1a6a07b /drivers/s390
parentb4d72c08b358fc5b259fad0f4971112d949efd1c (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.c33
-rw-r--r--drivers/s390/cio/chsc.h51
-rw-r--r--drivers/s390/cio/qdio_main.c91
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}
1236EXPORT_SYMBOL_GPL(chsc_scm_info); 1237EXPORT_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 */
1250int 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}
1269EXPORT_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
67extern struct css_chsc_char css_chsc_characteristics; 69extern struct css_chsc_char css_chsc_characteristics;
@@ -188,6 +190,53 @@ struct chsc_scm_info {
188 190
189int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token); 191int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token);
190 192
193struct chsc_brinfo_resume_token {
194 u64 t1;
195 u64 t2;
196} __packed;
197
198struct 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
207struct 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
235int 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
192int scm_update_information(void); 241int scm_update_information(void);
193int scm_process_availability_information(void); 242int 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}
1753EXPORT_SYMBOL(qdio_stop_irq); 1753EXPORT_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 */
1772int 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
1840out:
1841 free_page((unsigned long)rr);
1842 return rc;
1843}
1844EXPORT_SYMBOL_GPL(qdio_pnso_brinfo);
1845
1755static int __init init_QDIO(void) 1846static int __init init_QDIO(void)
1756{ 1847{
1757 int rc; 1848 int rc;