1618 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * S/390 common I/O routines -- channel subsystem call4 *5 * Copyright IBM Corp. 1999,20126 * Author(s): Ingo Adlung (adlung@de.ibm.com)7 * Cornelia Huck (cornelia.huck@de.ibm.com)8 * Arnd Bergmann (arndb@de.ibm.com)9 */10 11#define KMSG_COMPONENT "cio"12#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt13 14#include <linux/module.h>15#include <linux/slab.h>16#include <linux/init.h>17#include <linux/device.h>18#include <linux/mutex.h>19#include <linux/pci.h>20 21#include <asm/cio.h>22#include <asm/chpid.h>23#include <asm/chsc.h>24#include <asm/crw.h>25#include <asm/isc.h>26#include <asm/ebcdic.h>27 28#include "css.h"29#include "cio.h"30#include "cio_debug.h"31#include "ioasm.h"32#include "chp.h"33#include "chsc.h"34 35static void *sei_page;36static void *chsc_page;37static DEFINE_SPINLOCK(chsc_page_lock);38 39#define SEI_VF_FLA 0xc0 /* VF flag for Full Link Address */40#define SEI_RS_CHPID 0x4 /* 4 in RS field indicates CHPID */41 42static BLOCKING_NOTIFIER_HEAD(chsc_notifiers);43 44int chsc_notifier_register(struct notifier_block *nb)45{46 return blocking_notifier_chain_register(&chsc_notifiers, nb);47}48EXPORT_SYMBOL(chsc_notifier_register);49 50int chsc_notifier_unregister(struct notifier_block *nb)51{52 return blocking_notifier_chain_unregister(&chsc_notifiers, nb);53}54EXPORT_SYMBOL(chsc_notifier_unregister);55 56/**57 * chsc_error_from_response() - convert a chsc response to an error58 * @response: chsc response code59 *60 * Returns an appropriate Linux error code for @response.61 */62int chsc_error_from_response(int response)63{64 switch (response) {65 case 0x0001:66 return 0;67 case 0x0002:68 case 0x0003:69 case 0x0006:70 case 0x0007:71 case 0x0008:72 case 0x000a:73 case 0x0104:74 return -EINVAL;75 case 0x0004:76 case 0x0106: /* "Wrong Channel Parm" for the op 0x003d */77 return -EOPNOTSUPP;78 case 0x000b:79 case 0x0107: /* "Channel busy" for the op 0x003d */80 return -EBUSY;81 case 0x0100:82 case 0x0102:83 return -ENOMEM;84 case 0x0108: /* "HW limit exceeded" for the op 0x003d */85 return -EUSERS;86 default:87 return -EIO;88 }89}90EXPORT_SYMBOL_GPL(chsc_error_from_response);91 92struct chsc_ssd_area {93 struct chsc_header request;94 u16 :10;95 u16 ssid:2;96 u16 :4;97 u16 f_sch; /* first subchannel */98 u16 :16;99 u16 l_sch; /* last subchannel */100 u32 :32;101 struct chsc_header response;102 u32 :32;103 u8 sch_valid : 1;104 u8 dev_valid : 1;105 u8 st : 3; /* subchannel type */106 u8 zeroes : 3;107 u8 unit_addr; /* unit address */108 u16 devno; /* device number */109 u8 path_mask;110 u8 fla_valid_mask;111 u16 sch; /* subchannel */112 u8 chpid[8]; /* chpids 0-7 */113 u16 fla[8]; /* full link addresses 0-7 */114} __packed __aligned(PAGE_SIZE);115 116int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)117{118 struct chsc_ssd_area *ssd_area;119 unsigned long flags;120 int ccode;121 int ret;122 int i;123 int mask;124 125 spin_lock_irqsave(&chsc_page_lock, flags);126 memset(chsc_page, 0, PAGE_SIZE);127 ssd_area = chsc_page;128 ssd_area->request.length = 0x0010;129 ssd_area->request.code = 0x0004;130 ssd_area->ssid = schid.ssid;131 ssd_area->f_sch = schid.sch_no;132 ssd_area->l_sch = schid.sch_no;133 134 ccode = chsc(ssd_area);135 /* Check response. */136 if (ccode > 0) {137 ret = (ccode == 3) ? -ENODEV : -EBUSY;138 goto out;139 }140 ret = chsc_error_from_response(ssd_area->response.code);141 if (ret != 0) {142 CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n",143 schid.ssid, schid.sch_no,144 ssd_area->response.code);145 goto out;146 }147 if (!ssd_area->sch_valid) {148 ret = -ENODEV;149 goto out;150 }151 /* Copy data */152 ret = 0;153 memset(ssd, 0, sizeof(struct chsc_ssd_info));154 if ((ssd_area->st != SUBCHANNEL_TYPE_IO) &&155 (ssd_area->st != SUBCHANNEL_TYPE_MSG))156 goto out;157 ssd->path_mask = ssd_area->path_mask;158 ssd->fla_valid_mask = ssd_area->fla_valid_mask;159 for (i = 0; i < 8; i++) {160 mask = 0x80 >> i;161 if (ssd_area->path_mask & mask) {162 chp_id_init(&ssd->chpid[i]);163 ssd->chpid[i].id = ssd_area->chpid[i];164 }165 if (ssd_area->fla_valid_mask & mask)166 ssd->fla[i] = ssd_area->fla[i];167 }168out:169 spin_unlock_irqrestore(&chsc_page_lock, flags);170 return ret;171}172 173/**174 * chsc_ssqd() - store subchannel QDIO data (SSQD)175 * @schid: id of the subchannel on which SSQD is performed176 * @ssqd: request and response block for SSQD177 *178 * Returns 0 on success.179 */180int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd)181{182 memset(ssqd, 0, sizeof(*ssqd));183 ssqd->request.length = 0x0010;184 ssqd->request.code = 0x0024;185 ssqd->first_sch = schid.sch_no;186 ssqd->last_sch = schid.sch_no;187 ssqd->ssid = schid.ssid;188 189 if (chsc(ssqd))190 return -EIO;191 192 return chsc_error_from_response(ssqd->response.code);193}194EXPORT_SYMBOL_GPL(chsc_ssqd);195 196/**197 * chsc_sadc() - set adapter device controls (SADC)198 * @schid: id of the subchannel on which SADC is performed199 * @scssc: request and response block for SADC200 * @summary_indicator_addr: summary indicator address201 * @subchannel_indicator_addr: subchannel indicator address202 * @isc: Interruption Subclass for this subchannel203 *204 * Returns 0 on success.205 */206int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc,207 dma64_t summary_indicator_addr, dma64_t subchannel_indicator_addr, u8 isc)208{209 memset(scssc, 0, sizeof(*scssc));210 scssc->request.length = 0x0fe0;211 scssc->request.code = 0x0021;212 scssc->operation_code = 0;213 214 scssc->summary_indicator_addr = summary_indicator_addr;215 scssc->subchannel_indicator_addr = subchannel_indicator_addr;216 217 scssc->ks = PAGE_DEFAULT_KEY >> 4;218 scssc->kc = PAGE_DEFAULT_KEY >> 4;219 scssc->isc = isc;220 scssc->schid = schid;221 222 /* enable the time delay disablement facility */223 if (css_general_characteristics.aif_tdd)224 scssc->word_with_d_bit = 0x10000000;225 226 if (chsc(scssc))227 return -EIO;228 229 return chsc_error_from_response(scssc->response.code);230}231EXPORT_SYMBOL_GPL(chsc_sadc);232 233static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data)234{235 spin_lock_irq(&sch->lock);236 if (sch->driver && sch->driver->chp_event)237 if (sch->driver->chp_event(sch, data, CHP_OFFLINE) != 0)238 goto out_unreg;239 spin_unlock_irq(&sch->lock);240 return 0;241 242out_unreg:243 sch->lpm = 0;244 spin_unlock_irq(&sch->lock);245 css_schedule_eval(sch->schid);246 return 0;247}248 249void chsc_chp_offline(struct chp_id chpid)250{251 struct channel_path *chp = chpid_to_chp(chpid);252 struct chp_link link;253 char dbf_txt[15];254 255 sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id);256 CIO_TRACE_EVENT(2, dbf_txt);257 258 if (chp_get_status(chpid) <= 0)259 return;260 memset(&link, 0, sizeof(struct chp_link));261 link.chpid = chpid;262 /* Wait until previous actions have settled. */263 css_wait_for_slow_path();264 265 mutex_lock(&chp->lock);266 chp_update_desc(chp);267 mutex_unlock(&chp->lock);268 269 for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link);270}271 272static int __s390_process_res_acc(struct subchannel *sch, void *data)273{274 spin_lock_irq(&sch->lock);275 if (sch->driver && sch->driver->chp_event)276 sch->driver->chp_event(sch, data, CHP_ONLINE);277 spin_unlock_irq(&sch->lock);278 279 return 0;280}281 282static void s390_process_res_acc(struct chp_link *link)283{284 char dbf_txt[15];285 286 sprintf(dbf_txt, "accpr%x.%02x", link->chpid.cssid,287 link->chpid.id);288 CIO_TRACE_EVENT( 2, dbf_txt);289 if (link->fla != 0) {290 sprintf(dbf_txt, "fla%x", link->fla);291 CIO_TRACE_EVENT( 2, dbf_txt);292 }293 /* Wait until previous actions have settled. */294 css_wait_for_slow_path();295 /*296 * I/O resources may have become accessible.297 * Scan through all subchannels that may be concerned and298 * do a validation on those.299 * The more information we have (info), the less scanning300 * will we have to do.301 */302 for_each_subchannel_staged(__s390_process_res_acc, NULL, link);303 css_schedule_reprobe();304}305 306static int process_fces_event(struct subchannel *sch, void *data)307{308 spin_lock_irq(&sch->lock);309 if (sch->driver && sch->driver->chp_event)310 sch->driver->chp_event(sch, data, CHP_FCES_EVENT);311 spin_unlock_irq(&sch->lock);312 return 0;313}314 315struct chsc_sei_nt0_area {316 u8 flags;317 u8 vf; /* validity flags */318 u8 rs; /* reporting source */319 u8 cc; /* content code */320 u16 fla; /* full link address */321 u16 rsid; /* reporting source id */322 u32 reserved1;323 u32 reserved2;324 /* ccdf has to be big enough for a link-incident record */325 u8 ccdf[PAGE_SIZE - 24 - 16]; /* content-code dependent field */326} __packed;327 328struct chsc_sei_nt2_area {329 u8 flags; /* p and v bit */330 u8 reserved1;331 u8 reserved2;332 u8 cc; /* content code */333 u32 reserved3[13];334 u8 ccdf[PAGE_SIZE - 24 - 56]; /* content-code dependent field */335} __packed;336 337#define CHSC_SEI_NT0 (1ULL << 63)338#define CHSC_SEI_NT2 (1ULL << 61)339 340struct chsc_sei {341 struct chsc_header request;342 u32 reserved1;343 u64 ntsm; /* notification type mask */344 struct chsc_header response;345 u32 :24;346 u8 nt;347 union {348 struct chsc_sei_nt0_area nt0_area;349 struct chsc_sei_nt2_area nt2_area;350 u8 nt_area[PAGE_SIZE - 24];351 } u;352} __packed __aligned(PAGE_SIZE);353 354/*355 * Link Incident Record as defined in SA22-7202, "ESCON I/O Interface"356 */357 358#define LIR_IQ_CLASS_INFO 0359#define LIR_IQ_CLASS_DEGRADED 1360#define LIR_IQ_CLASS_NOT_OPERATIONAL 2361 362struct lir {363 struct {364 u32 null:1;365 u32 reserved:3;366 u32 class:2;367 u32 reserved2:2;368 } __packed iq;369 u32 ic:8;370 u32 reserved:16;371 struct node_descriptor incident_node;372 struct node_descriptor attached_node;373 u8 reserved2[32];374} __packed;375 376#define PARAMS_LEN 10 /* PARAMS=xx,xxxxxx */377#define NODEID_LEN 35 /* NODEID=tttttt/mdl,mmm.ppssssssssssss,xxxx */378 379/* Copy EBCIDC text, convert to ASCII and optionally add delimiter. */380static char *store_ebcdic(char *dest, const char *src, unsigned long len,381 char delim)382{383 memcpy(dest, src, len);384 EBCASC(dest, len);385 386 if (delim)387 dest[len++] = delim;388 389 return dest + len;390}391 392static void chsc_link_from_sei(struct chp_link *link,393 struct chsc_sei_nt0_area *sei_area)394{395 if ((sei_area->vf & SEI_VF_FLA) != 0) {396 link->fla = sei_area->fla;397 link->fla_mask = ((sei_area->vf & SEI_VF_FLA) == SEI_VF_FLA) ?398 0xffff : 0xff00;399 }400}401 402/* Format node ID and parameters for output in LIR log message. */403static void format_node_data(char *params, char *id, struct node_descriptor *nd)404{405 memset(params, 0, PARAMS_LEN);406 memset(id, 0, NODEID_LEN);407 408 if (nd->validity != ND_VALIDITY_VALID) {409 strscpy(params, "n/a", PARAMS_LEN);410 strscpy(id, "n/a", NODEID_LEN);411 return;412 }413 414 /* PARAMS=xx,xxxxxx */415 snprintf(params, PARAMS_LEN, "%02x,%06x", nd->byte0, nd->params);416 /* NODEID=tttttt/mdl,mmm.ppssssssssssss,xxxx */417 id = store_ebcdic(id, nd->type, sizeof(nd->type), '/');418 id = store_ebcdic(id, nd->model, sizeof(nd->model), ',');419 id = store_ebcdic(id, nd->manufacturer, sizeof(nd->manufacturer), '.');420 id = store_ebcdic(id, nd->plant, sizeof(nd->plant), 0);421 id = store_ebcdic(id, nd->seq, sizeof(nd->seq), ',');422 sprintf(id, "%04X", nd->tag);423}424 425static void chsc_process_sei_link_incident(struct chsc_sei_nt0_area *sei_area)426{427 struct lir *lir = (struct lir *) &sei_area->ccdf;428 char iuparams[PARAMS_LEN], iunodeid[NODEID_LEN], auparams[PARAMS_LEN],429 aunodeid[NODEID_LEN];430 431 CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x, iq=%02x)\n",432 sei_area->rs, sei_area->rsid, sei_area->ccdf[0]);433 434 /* Ignore NULL Link Incident Records. */435 if (lir->iq.null)436 return;437 438 /* Inform user that a link requires maintenance actions because it has439 * become degraded or not operational. Note that this log message is440 * the primary intention behind a Link Incident Record. */441 442 format_node_data(iuparams, iunodeid, &lir->incident_node);443 format_node_data(auparams, aunodeid, &lir->attached_node);444 445 switch (lir->iq.class) {446 case LIR_IQ_CLASS_DEGRADED:447 pr_warn("Link degraded: RS=%02x RSID=%04x IC=%02x "448 "IUPARAMS=%s IUNODEID=%s AUPARAMS=%s AUNODEID=%s\n",449 sei_area->rs, sei_area->rsid, lir->ic, iuparams,450 iunodeid, auparams, aunodeid);451 break;452 case LIR_IQ_CLASS_NOT_OPERATIONAL:453 pr_err("Link stopped: RS=%02x RSID=%04x IC=%02x "454 "IUPARAMS=%s IUNODEID=%s AUPARAMS=%s AUNODEID=%s\n",455 sei_area->rs, sei_area->rsid, lir->ic, iuparams,456 iunodeid, auparams, aunodeid);457 break;458 default:459 break;460 }461}462 463static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area)464{465 struct channel_path *chp;466 struct chp_link link;467 struct chp_id chpid;468 int status;469 470 CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, "471 "rs_id=%04x)\n", sei_area->rs, sei_area->rsid);472 if (sei_area->rs != 4)473 return;474 chp_id_init(&chpid);475 chpid.id = sei_area->rsid;476 /* allocate a new channel path structure, if needed */477 status = chp_get_status(chpid);478 if (!status)479 return;480 481 if (status < 0) {482 chp_new(chpid);483 } else {484 chp = chpid_to_chp(chpid);485 mutex_lock(&chp->lock);486 chp_update_desc(chp);487 mutex_unlock(&chp->lock);488 }489 memset(&link, 0, sizeof(struct chp_link));490 link.chpid = chpid;491 chsc_link_from_sei(&link, sei_area);492 s390_process_res_acc(&link);493}494 495static void chsc_process_sei_chp_avail(struct chsc_sei_nt0_area *sei_area)496{497 struct channel_path *chp;498 struct chp_id chpid;499 u8 *data;500 int num;501 502 CIO_CRW_EVENT(4, "chsc: channel path availability information\n");503 if (sei_area->rs != 0)504 return;505 data = sei_area->ccdf;506 chp_id_init(&chpid);507 for (num = 0; num <= __MAX_CHPID; num++) {508 if (!chp_test_bit(data, num))509 continue;510 chpid.id = num;511 512 CIO_CRW_EVENT(4, "Update information for channel path "513 "%x.%02x\n", chpid.cssid, chpid.id);514 chp = chpid_to_chp(chpid);515 if (!chp) {516 chp_new(chpid);517 continue;518 }519 mutex_lock(&chp->lock);520 chp_update_desc(chp);521 mutex_unlock(&chp->lock);522 }523}524 525struct chp_config_data {526 u8 map[32];527 u8 op;528 u8 pc;529};530 531static void chsc_process_sei_chp_config(struct chsc_sei_nt0_area *sei_area)532{533 struct chp_config_data *data;534 struct chp_id chpid;535 int num;536 char *events[3] = {"configure", "deconfigure", "cancel deconfigure"};537 538 CIO_CRW_EVENT(4, "chsc: channel-path-configuration notification\n");539 if (sei_area->rs != 0)540 return;541 data = (struct chp_config_data *) &(sei_area->ccdf);542 chp_id_init(&chpid);543 for (num = 0; num <= __MAX_CHPID; num++) {544 if (!chp_test_bit(data->map, num))545 continue;546 chpid.id = num;547 pr_notice("Processing %s for channel path %x.%02x\n",548 events[data->op], chpid.cssid, chpid.id);549 switch (data->op) {550 case 0:551 chp_cfg_schedule(chpid, 1);552 break;553 case 1:554 chp_cfg_schedule(chpid, 0);555 break;556 case 2:557 chp_cfg_cancel_deconfigure(chpid);558 break;559 }560 }561}562 563static void chsc_process_sei_scm_change(struct chsc_sei_nt0_area *sei_area)564{565 int ret;566 567 CIO_CRW_EVENT(4, "chsc: scm change notification\n");568 if (sei_area->rs != 7)569 return;570 571 ret = scm_update_information();572 if (ret)573 CIO_CRW_EVENT(0, "chsc: updating change notification"574 " failed (rc=%d).\n", ret);575}576 577static void chsc_process_sei_scm_avail(struct chsc_sei_nt0_area *sei_area)578{579 int ret;580 581 CIO_CRW_EVENT(4, "chsc: scm available information\n");582 if (sei_area->rs != 7)583 return;584 585 ret = scm_process_availability_information();586 if (ret)587 CIO_CRW_EVENT(0, "chsc: process availability information"588 " failed (rc=%d).\n", ret);589}590 591static void chsc_process_sei_ap_cfg_chg(struct chsc_sei_nt0_area *sei_area)592{593 CIO_CRW_EVENT(3, "chsc: ap config changed\n");594 if (sei_area->rs != 5)595 return;596 597 blocking_notifier_call_chain(&chsc_notifiers,598 CHSC_NOTIFY_AP_CFG, NULL);599}600 601static void chsc_process_sei_fces_event(struct chsc_sei_nt0_area *sei_area)602{603 struct chp_link link;604 struct chp_id chpid;605 struct channel_path *chp;606 607 CIO_CRW_EVENT(4,608 "chsc: FCES status notification (rs=%02x, rs_id=%04x, FCES-status=%x)\n",609 sei_area->rs, sei_area->rsid, sei_area->ccdf[0]);610 611 if (sei_area->rs != SEI_RS_CHPID)612 return;613 chp_id_init(&chpid);614 chpid.id = sei_area->rsid;615 616 /* Ignore the event on unknown/invalid chp */617 chp = chpid_to_chp(chpid);618 if (!chp)619 return;620 621 memset(&link, 0, sizeof(struct chp_link));622 link.chpid = chpid;623 chsc_link_from_sei(&link, sei_area);624 625 for_each_subchannel_staged(process_fces_event, NULL, &link);626}627 628static void chsc_process_sei_nt2(struct chsc_sei_nt2_area *sei_area)629{630 switch (sei_area->cc) {631 case 1:632 zpci_event_error(sei_area->ccdf);633 break;634 case 2:635 zpci_event_availability(sei_area->ccdf);636 break;637 default:638 CIO_CRW_EVENT(2, "chsc: sei nt2 unhandled cc=%d\n",639 sei_area->cc);640 break;641 }642}643 644static void chsc_process_sei_nt0(struct chsc_sei_nt0_area *sei_area)645{646 /* which kind of information was stored? */647 switch (sei_area->cc) {648 case 1: /* link incident*/649 chsc_process_sei_link_incident(sei_area);650 break;651 case 2: /* i/o resource accessibility */652 chsc_process_sei_res_acc(sei_area);653 break;654 case 3: /* ap config changed */655 chsc_process_sei_ap_cfg_chg(sei_area);656 break;657 case 7: /* channel-path-availability information */658 chsc_process_sei_chp_avail(sei_area);659 break;660 case 8: /* channel-path-configuration notification */661 chsc_process_sei_chp_config(sei_area);662 break;663 case 12: /* scm change notification */664 chsc_process_sei_scm_change(sei_area);665 break;666 case 14: /* scm available notification */667 chsc_process_sei_scm_avail(sei_area);668 break;669 case 15: /* FCES event notification */670 chsc_process_sei_fces_event(sei_area);671 break;672 default: /* other stuff */673 CIO_CRW_EVENT(2, "chsc: sei nt0 unhandled cc=%d\n",674 sei_area->cc);675 break;676 }677 678 /* Check if we might have lost some information. */679 if (sei_area->flags & 0x40) {680 CIO_CRW_EVENT(2, "chsc: event overflow\n");681 css_schedule_eval_all();682 }683}684 685static void chsc_process_event_information(struct chsc_sei *sei, u64 ntsm)686{687 static int ntsm_unsupported;688 689 while (true) {690 memset(sei, 0, sizeof(*sei));691 sei->request.length = 0x0010;692 sei->request.code = 0x000e;693 if (!ntsm_unsupported)694 sei->ntsm = ntsm;695 696 if (chsc(sei))697 break;698 699 if (sei->response.code != 0x0001) {700 CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x, ntsm=%llx)\n",701 sei->response.code, sei->ntsm);702 703 if (sei->response.code == 3 && sei->ntsm) {704 /* Fallback for old firmware. */705 ntsm_unsupported = 1;706 continue;707 }708 break;709 }710 711 CIO_CRW_EVENT(2, "chsc: sei successful (nt=%d)\n", sei->nt);712 switch (sei->nt) {713 case 0:714 chsc_process_sei_nt0(&sei->u.nt0_area);715 break;716 case 2:717 chsc_process_sei_nt2(&sei->u.nt2_area);718 break;719 default:720 CIO_CRW_EVENT(2, "chsc: unhandled nt: %d\n", sei->nt);721 break;722 }723 724 if (!(sei->u.nt0_area.flags & 0x80))725 break;726 }727}728 729/*730 * Handle channel subsystem related CRWs.731 * Use store event information to find out what's going on.732 *733 * Note: Access to sei_page is serialized through machine check handler734 * thread, so no need for locking.735 */736static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)737{738 struct chsc_sei *sei = sei_page;739 740 if (overflow) {741 css_schedule_eval_all();742 return;743 }744 CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, "745 "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",746 crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,747 crw0->erc, crw0->rsid);748 749 CIO_TRACE_EVENT(2, "prcss");750 chsc_process_event_information(sei, CHSC_SEI_NT0 | CHSC_SEI_NT2);751}752 753void chsc_chp_online(struct chp_id chpid)754{755 struct channel_path *chp = chpid_to_chp(chpid);756 struct chp_link link;757 char dbf_txt[15];758 759 sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id);760 CIO_TRACE_EVENT(2, dbf_txt);761 762 if (chp_get_status(chpid) != 0) {763 memset(&link, 0, sizeof(struct chp_link));764 link.chpid = chpid;765 /* Wait until previous actions have settled. */766 css_wait_for_slow_path();767 768 mutex_lock(&chp->lock);769 chp_update_desc(chp);770 mutex_unlock(&chp->lock);771 772 for_each_subchannel_staged(__s390_process_res_acc, NULL,773 &link);774 css_schedule_reprobe();775 }776}777 778static void __s390_subchannel_vary_chpid(struct subchannel *sch,779 struct chp_id chpid, int on)780{781 unsigned long flags;782 struct chp_link link;783 784 memset(&link, 0, sizeof(struct chp_link));785 link.chpid = chpid;786 spin_lock_irqsave(&sch->lock, flags);787 if (sch->driver && sch->driver->chp_event)788 sch->driver->chp_event(sch, &link,789 on ? CHP_VARY_ON : CHP_VARY_OFF);790 spin_unlock_irqrestore(&sch->lock, flags);791}792 793static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data)794{795 struct chp_id *chpid = data;796 797 __s390_subchannel_vary_chpid(sch, *chpid, 0);798 return 0;799}800 801static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data)802{803 struct chp_id *chpid = data;804 805 __s390_subchannel_vary_chpid(sch, *chpid, 1);806 return 0;807}808 809/**810 * chsc_chp_vary - propagate channel-path vary operation to subchannels811 * @chpid: channl-path ID812 * @on: non-zero for vary online, zero for vary offline813 */814int chsc_chp_vary(struct chp_id chpid, int on)815{816 struct channel_path *chp = chpid_to_chp(chpid);817 818 /*819 * Redo PathVerification on the devices the chpid connects to820 */821 if (on) {822 /* Try to update the channel path description. */823 chp_update_desc(chp);824 for_each_subchannel_staged(s390_subchannel_vary_chpid_on,825 NULL, &chpid);826 css_schedule_reprobe();827 } else828 for_each_subchannel_staged(s390_subchannel_vary_chpid_off,829 NULL, &chpid);830 831 return 0;832}833 834static void835chsc_remove_cmg_attr(struct channel_subsystem *css)836{837 int i;838 839 for (i = 0; i <= __MAX_CHPID; i++) {840 if (!css->chps[i])841 continue;842 chp_remove_cmg_attr(css->chps[i]);843 }844}845 846static int847chsc_add_cmg_attr(struct channel_subsystem *css)848{849 int i, ret;850 851 ret = 0;852 for (i = 0; i <= __MAX_CHPID; i++) {853 if (!css->chps[i])854 continue;855 ret = chp_add_cmg_attr(css->chps[i]);856 if (ret)857 goto cleanup;858 }859 return ret;860cleanup:861 while (i--) {862 if (!css->chps[i])863 continue;864 chp_remove_cmg_attr(css->chps[i]);865 }866 return ret;867}868 869int __chsc_do_secm(struct channel_subsystem *css, int enable)870{871 struct {872 struct chsc_header request;873 u32 operation_code : 2;874 u32 : 1;875 u32 e : 1;876 u32 : 28;877 u32 key : 4;878 u32 : 28;879 dma64_t cub[CSS_NUM_CUB_PAGES];880 dma64_t ecub[CSS_NUM_ECUB_PAGES];881 u32 reserved[5];882 struct chsc_header response;883 u32 status : 8;884 u32 : 4;885 u32 fmt : 4;886 u32 : 16;887 } __packed *secm_area;888 unsigned long flags;889 int ret, ccode, i;890 891 spin_lock_irqsave(&chsc_page_lock, flags);892 memset(chsc_page, 0, PAGE_SIZE);893 secm_area = chsc_page;894 secm_area->request.length = 0x0050;895 secm_area->request.code = 0x0016;896 897 secm_area->key = PAGE_DEFAULT_KEY >> 4;898 secm_area->e = 1;899 900 for (i = 0; i < CSS_NUM_CUB_PAGES; i++)901 secm_area->cub[i] = (__force dma64_t)virt_to_dma32(css->cub[i]);902 for (i = 0; i < CSS_NUM_ECUB_PAGES; i++)903 secm_area->ecub[i] = virt_to_dma64(css->ecub[i]);904 905 secm_area->operation_code = enable ? 0 : 1;906 907 ccode = chsc(secm_area);908 if (ccode > 0) {909 ret = (ccode == 3) ? -ENODEV : -EBUSY;910 goto out;911 }912 913 switch (secm_area->response.code) {914 case 0x0102:915 case 0x0103:916 ret = -EINVAL;917 break;918 default:919 ret = chsc_error_from_response(secm_area->response.code);920 }921 if (ret != 0)922 CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",923 secm_area->response.code);924out:925 spin_unlock_irqrestore(&chsc_page_lock, flags);926 return ret;927}928 929static int cub_alloc(struct channel_subsystem *css)930{931 int i;932 933 for (i = 0; i < CSS_NUM_CUB_PAGES; i++) {934 css->cub[i] = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);935 if (!css->cub[i])936 return -ENOMEM;937 }938 for (i = 0; i < CSS_NUM_ECUB_PAGES; i++) {939 css->ecub[i] = (void *)get_zeroed_page(GFP_KERNEL);940 if (!css->ecub[i])941 return -ENOMEM;942 }943 944 return 0;945}946 947static void cub_free(struct channel_subsystem *css)948{949 int i;950 951 for (i = 0; i < CSS_NUM_CUB_PAGES; i++) {952 free_page((unsigned long)css->cub[i]);953 css->cub[i] = NULL;954 }955 for (i = 0; i < CSS_NUM_ECUB_PAGES; i++) {956 free_page((unsigned long)css->ecub[i]);957 css->ecub[i] = NULL;958 }959}960 961int962chsc_secm(struct channel_subsystem *css, int enable)963{964 int ret;965 966 if (enable && !css->cm_enabled) {967 ret = cub_alloc(css);968 if (ret)969 goto out;970 }971 ret = __chsc_do_secm(css, enable);972 if (!ret) {973 css->cm_enabled = enable;974 if (css->cm_enabled) {975 ret = chsc_add_cmg_attr(css);976 if (ret) {977 __chsc_do_secm(css, 0);978 css->cm_enabled = 0;979 }980 } else981 chsc_remove_cmg_attr(css);982 }983 984out:985 if (!css->cm_enabled)986 cub_free(css);987 988 return ret;989}990 991int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,992 int c, int m, void *page)993{994 struct chsc_scpd *scpd_area;995 int ccode, ret;996 997 if ((rfmt == 1 || rfmt == 0) && c == 1 &&998 !css_general_characteristics.fcs)999 return -EINVAL;1000 if ((rfmt == 2) && !css_general_characteristics.cib)1001 return -EINVAL;1002 if ((rfmt == 3) && !css_general_characteristics.util_str)1003 return -EINVAL;1004 1005 memset(page, 0, PAGE_SIZE);1006 scpd_area = page;1007 scpd_area->request.length = 0x0010;1008 scpd_area->request.code = 0x0002;1009 scpd_area->cssid = chpid.cssid;1010 scpd_area->first_chpid = chpid.id;1011 scpd_area->last_chpid = chpid.id;1012 scpd_area->m = m;1013 scpd_area->c = c;1014 scpd_area->fmt = fmt;1015 scpd_area->rfmt = rfmt;1016 1017 ccode = chsc(scpd_area);1018 if (ccode > 0)1019 return (ccode == 3) ? -ENODEV : -EBUSY;1020 1021 ret = chsc_error_from_response(scpd_area->response.code);1022 if (ret)1023 CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n",1024 scpd_area->response.code);1025 return ret;1026}1027EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc);1028 1029#define chsc_det_chp_desc(FMT, c) \1030int chsc_determine_fmt##FMT##_channel_path_desc( \1031 struct chp_id chpid, struct channel_path_desc_fmt##FMT *desc) \1032{ \1033 struct chsc_scpd *scpd_area; \1034 unsigned long flags; \1035 int ret; \1036 \1037 spin_lock_irqsave(&chsc_page_lock, flags); \1038 scpd_area = chsc_page; \1039 ret = chsc_determine_channel_path_desc(chpid, 0, FMT, c, 0, \1040 scpd_area); \1041 if (ret) \1042 goto out; \1043 \1044 memcpy(desc, scpd_area->data, sizeof(*desc)); \1045out: \1046 spin_unlock_irqrestore(&chsc_page_lock, flags); \1047 return ret; \1048}1049 1050chsc_det_chp_desc(0, 0)1051chsc_det_chp_desc(1, 1)1052chsc_det_chp_desc(3, 0)1053 1054static void1055chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,1056 struct cmg_chars *chars)1057{1058 int i, mask;1059 1060 for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {1061 mask = 0x80 >> (i + 3);1062 if (cmcv & mask)1063 chp->cmg_chars.values[i] = chars->values[i];1064 else1065 chp->cmg_chars.values[i] = 0;1066 }1067}1068 1069static unsigned long scmc_get_speed(u32 s, u32 p)1070{1071 unsigned long speed = s;1072 1073 if (!p)1074 p = 8;1075 while (p--)1076 speed *= 10;1077 1078 return speed;1079}1080 1081int chsc_get_channel_measurement_chars(struct channel_path *chp)1082{1083 unsigned long flags;1084 int ccode, ret;1085 1086 struct {1087 struct chsc_header request;1088 u32 : 24;1089 u32 first_chpid : 8;1090 u32 : 24;1091 u32 last_chpid : 8;1092 u32 zeroes1;1093 struct chsc_header response;1094 u32 zeroes2;1095 u32 not_valid : 1;1096 u32 shared : 1;1097 u32 extended : 1;1098 u32 : 21;1099 u32 chpid : 8;1100 u32 cmcv : 5;1101 u32 : 7;1102 u32 cmgp : 4;1103 u32 cmgq : 8;1104 u32 cmg : 8;1105 u32 : 16;1106 u32 cmgs : 16;1107 u32 data[NR_MEASUREMENT_CHARS];1108 } *scmc_area;1109 1110 chp->shared = -1;1111 chp->cmg = -1;1112 chp->extended = 0;1113 chp->speed = 0;1114 1115 if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm)1116 return -EINVAL;1117 1118 spin_lock_irqsave(&chsc_page_lock, flags);1119 memset(chsc_page, 0, PAGE_SIZE);1120 scmc_area = chsc_page;1121 scmc_area->request.length = 0x0010;1122 scmc_area->request.code = 0x0022;1123 scmc_area->first_chpid = chp->chpid.id;1124 scmc_area->last_chpid = chp->chpid.id;1125 1126 ccode = chsc(scmc_area);1127 if (ccode > 0) {1128 ret = (ccode == 3) ? -ENODEV : -EBUSY;1129 goto out;1130 }1131 1132 ret = chsc_error_from_response(scmc_area->response.code);1133 if (ret) {1134 CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n",1135 scmc_area->response.code);1136 goto out;1137 }1138 if (scmc_area->not_valid)1139 goto out;1140 1141 chp->cmg = scmc_area->cmg;1142 chp->shared = scmc_area->shared;1143 chp->extended = scmc_area->extended;1144 chp->speed = scmc_get_speed(scmc_area->cmgs, scmc_area->cmgp);1145 chsc_initialize_cmg_chars(chp, scmc_area->cmcv,1146 (struct cmg_chars *) &scmc_area->data);1147out:1148 spin_unlock_irqrestore(&chsc_page_lock, flags);1149 return ret;1150}1151 1152int __init chsc_init(void)1153{1154 int ret;1155 1156 sei_page = (void *)get_zeroed_page(GFP_KERNEL);1157 chsc_page = (void *)get_zeroed_page(GFP_KERNEL);1158 if (!sei_page || !chsc_page) {1159 ret = -ENOMEM;1160 goto out_err;1161 }1162 ret = crw_register_handler(CRW_RSC_CSS, chsc_process_crw);1163 if (ret)1164 goto out_err;1165 return ret;1166out_err:1167 free_page((unsigned long)chsc_page);1168 free_page((unsigned long)sei_page);1169 return ret;1170}1171 1172void __init chsc_init_cleanup(void)1173{1174 crw_unregister_handler(CRW_RSC_CSS);1175 free_page((unsigned long)chsc_page);1176 free_page((unsigned long)sei_page);1177}1178 1179int __chsc_enable_facility(struct chsc_sda_area *sda_area, int operation_code)1180{1181 int ret;1182 1183 sda_area->request.length = 0x0400;1184 sda_area->request.code = 0x0031;1185 sda_area->operation_code = operation_code;1186 1187 ret = chsc(sda_area);1188 if (ret > 0) {1189 ret = (ret == 3) ? -ENODEV : -EBUSY;1190 goto out;1191 }1192 1193 switch (sda_area->response.code) {1194 case 0x0101:1195 ret = -EOPNOTSUPP;1196 break;1197 default:1198 ret = chsc_error_from_response(sda_area->response.code);1199 }1200out:1201 return ret;1202}1203 1204int chsc_enable_facility(int operation_code)1205{1206 struct chsc_sda_area *sda_area;1207 unsigned long flags;1208 int ret;1209 1210 spin_lock_irqsave(&chsc_page_lock, flags);1211 memset(chsc_page, 0, PAGE_SIZE);1212 sda_area = chsc_page;1213 1214 ret = __chsc_enable_facility(sda_area, operation_code);1215 if (ret != 0)1216 CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",1217 operation_code, sda_area->response.code);1218 1219 spin_unlock_irqrestore(&chsc_page_lock, flags);1220 return ret;1221}1222 1223int __init chsc_get_cssid_iid(int idx, u8 *cssid, u8 *iid)1224{1225 struct {1226 struct chsc_header request;1227 u8 atype;1228 u32 : 24;1229 u32 reserved1[6];1230 struct chsc_header response;1231 u32 reserved2[3];1232 struct {1233 u8 cssid;1234 u8 iid;1235 u32 : 16;1236 } list[];1237 } *sdcal_area;1238 int ret;1239 1240 spin_lock_irq(&chsc_page_lock);1241 memset(chsc_page, 0, PAGE_SIZE);1242 sdcal_area = chsc_page;1243 sdcal_area->request.length = 0x0020;1244 sdcal_area->request.code = 0x0034;1245 sdcal_area->atype = 4;1246 1247 ret = chsc(sdcal_area);1248 if (ret) {1249 ret = (ret == 3) ? -ENODEV : -EBUSY;1250 goto exit;1251 }1252 1253 ret = chsc_error_from_response(sdcal_area->response.code);1254 if (ret) {1255 CIO_CRW_EVENT(2, "chsc: sdcal failed (rc=%04x)\n",1256 sdcal_area->response.code);1257 goto exit;1258 }1259 1260 if ((addr_t) &sdcal_area->list[idx] <1261 (addr_t) &sdcal_area->response + sdcal_area->response.length) {1262 *cssid = sdcal_area->list[idx].cssid;1263 *iid = sdcal_area->list[idx].iid;1264 }1265 else1266 ret = -ENODEV;1267exit:1268 spin_unlock_irq(&chsc_page_lock);1269 return ret;1270}1271 1272struct css_general_char css_general_characteristics;1273struct css_chsc_char css_chsc_characteristics;1274 1275int __init1276chsc_determine_css_characteristics(void)1277{1278 unsigned long flags;1279 int result;1280 struct {1281 struct chsc_header request;1282 u32 reserved1;1283 u32 reserved2;1284 u32 reserved3;1285 struct chsc_header response;1286 u32 reserved4;1287 u32 general_char[510];1288 u32 chsc_char[508];1289 } *scsc_area;1290 1291 spin_lock_irqsave(&chsc_page_lock, flags);1292 memset(chsc_page, 0, PAGE_SIZE);1293 scsc_area = chsc_page;1294 scsc_area->request.length = 0x0010;1295 scsc_area->request.code = 0x0010;1296 1297 result = chsc(scsc_area);1298 if (result) {1299 result = (result == 3) ? -ENODEV : -EBUSY;1300 goto exit;1301 }1302 1303 result = chsc_error_from_response(scsc_area->response.code);1304 if (result == 0) {1305 memcpy(&css_general_characteristics, scsc_area->general_char,1306 sizeof(css_general_characteristics));1307 memcpy(&css_chsc_characteristics, scsc_area->chsc_char,1308 sizeof(css_chsc_characteristics));1309 } else1310 CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",1311 scsc_area->response.code);1312exit:1313 spin_unlock_irqrestore(&chsc_page_lock, flags);1314 return result;1315}1316 1317EXPORT_SYMBOL_GPL(css_general_characteristics);1318EXPORT_SYMBOL_GPL(css_chsc_characteristics);1319 1320int chsc_sstpc(void *page, unsigned int op, u16 ctrl, long *clock_delta)1321{1322 struct {1323 struct chsc_header request;1324 unsigned int rsvd0;1325 unsigned int op : 8;1326 unsigned int rsvd1 : 8;1327 unsigned int ctrl : 16;1328 unsigned int rsvd2[5];1329 struct chsc_header response;1330 unsigned int rsvd3[3];1331 s64 clock_delta;1332 unsigned int rsvd4[2];1333 } *rr;1334 int rc;1335 1336 memset(page, 0, PAGE_SIZE);1337 rr = page;1338 rr->request.length = 0x0020;1339 rr->request.code = 0x0033;1340 rr->op = op;1341 rr->ctrl = ctrl;1342 rc = chsc(rr);1343 if (rc)1344 return -EIO;1345 rc = (rr->response.code == 0x0001) ? 0 : -EIO;1346 if (clock_delta)1347 *clock_delta = rr->clock_delta;1348 return rc;1349}1350 1351int chsc_sstpi(void *page, void *result, size_t size)1352{1353 struct {1354 struct chsc_header request;1355 unsigned int rsvd0[3];1356 struct chsc_header response;1357 char data[];1358 } *rr;1359 int rc;1360 1361 memset(page, 0, PAGE_SIZE);1362 rr = page;1363 rr->request.length = 0x0010;1364 rr->request.code = 0x0038;1365 rc = chsc(rr);1366 if (rc)1367 return -EIO;1368 memcpy(result, &rr->data, size);1369 return (rr->response.code == 0x0001) ? 0 : -EIO;1370}1371 1372int chsc_stzi(void *page, void *result, size_t size)1373{1374 struct {1375 struct chsc_header request;1376 unsigned int rsvd0[3];1377 struct chsc_header response;1378 char data[];1379 } *rr;1380 int rc;1381 1382 memset(page, 0, PAGE_SIZE);1383 rr = page;1384 rr->request.length = 0x0010;1385 rr->request.code = 0x003e;1386 rc = chsc(rr);1387 if (rc)1388 return -EIO;1389 memcpy(result, &rr->data, size);1390 return (rr->response.code == 0x0001) ? 0 : -EIO;1391}1392 1393int chsc_siosl(struct subchannel_id schid)1394{1395 struct {1396 struct chsc_header request;1397 u32 word1;1398 struct subchannel_id sid;1399 u32 word3;1400 struct chsc_header response;1401 u32 word[11];1402 } *siosl_area;1403 unsigned long flags;1404 int ccode;1405 int rc;1406 1407 spin_lock_irqsave(&chsc_page_lock, flags);1408 memset(chsc_page, 0, PAGE_SIZE);1409 siosl_area = chsc_page;1410 siosl_area->request.length = 0x0010;1411 siosl_area->request.code = 0x0046;1412 siosl_area->word1 = 0x80000000;1413 siosl_area->sid = schid;1414 1415 ccode = chsc(siosl_area);1416 if (ccode > 0) {1417 if (ccode == 3)1418 rc = -ENODEV;1419 else1420 rc = -EBUSY;1421 CIO_MSG_EVENT(2, "chsc: chsc failed for 0.%x.%04x (ccode=%d)\n",1422 schid.ssid, schid.sch_no, ccode);1423 goto out;1424 }1425 rc = chsc_error_from_response(siosl_area->response.code);1426 if (rc)1427 CIO_MSG_EVENT(2, "chsc: siosl failed for 0.%x.%04x (rc=%04x)\n",1428 schid.ssid, schid.sch_no,1429 siosl_area->response.code);1430 else1431 CIO_MSG_EVENT(4, "chsc: siosl succeeded for 0.%x.%04x\n",1432 schid.ssid, schid.sch_no);1433out:1434 spin_unlock_irqrestore(&chsc_page_lock, flags);1435 return rc;1436}1437EXPORT_SYMBOL_GPL(chsc_siosl);1438 1439/**1440 * chsc_scm_info() - store SCM information (SSI)1441 * @scm_area: request and response block for SSI1442 * @token: continuation token1443 *1444 * Returns 0 on success.1445 */1446int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token)1447{1448 int ccode, ret;1449 1450 memset(scm_area, 0, sizeof(*scm_area));1451 scm_area->request.length = 0x0020;1452 scm_area->request.code = 0x004C;1453 scm_area->reqtok = token;1454 1455 ccode = chsc(scm_area);1456 if (ccode > 0) {1457 ret = (ccode == 3) ? -ENODEV : -EBUSY;1458 goto out;1459 }1460 ret = chsc_error_from_response(scm_area->response.code);1461 if (ret != 0)1462 CIO_MSG_EVENT(2, "chsc: scm info failed (rc=%04x)\n",1463 scm_area->response.code);1464out:1465 return ret;1466}1467EXPORT_SYMBOL_GPL(chsc_scm_info);1468 1469/**1470 * chsc_pnso() - Perform Network-Subchannel Operation1471 * @schid: id of the subchannel on which PNSO is performed1472 * @pnso_area: request and response block for the operation1473 * @oc: Operation Code1474 * @resume_token: resume token for multiblock response1475 * @cnc: Boolean change-notification control1476 *1477 * pnso_area must be allocated by the caller with get_zeroed_page(GFP_KERNEL)1478 *1479 * Returns 0 on success.1480 */1481int chsc_pnso(struct subchannel_id schid, struct chsc_pnso_area *pnso_area,1482 u8 oc, struct chsc_pnso_resume_token resume_token, int cnc)1483{1484 memset(pnso_area, 0, sizeof(*pnso_area));1485 pnso_area->request.length = 0x0030;1486 pnso_area->request.code = 0x003d; /* network-subchannel operation */1487 pnso_area->m = schid.m;1488 pnso_area->ssid = schid.ssid;1489 pnso_area->sch = schid.sch_no;1490 pnso_area->cssid = schid.cssid;1491 pnso_area->oc = oc;1492 pnso_area->resume_token = resume_token;1493 pnso_area->n = (cnc != 0);1494 if (chsc(pnso_area))1495 return -EIO;1496 return chsc_error_from_response(pnso_area->response.code);1497}1498 1499int chsc_sgib(u32 origin)1500{1501 struct {1502 struct chsc_header request;1503 u16 op;1504 u8 reserved01[2];1505 u8 reserved02:4;1506 u8 fmt:4;1507 u8 reserved03[7];1508 /* operation data area begin */1509 u8 reserved04[4];1510 u32 gib_origin;1511 u8 reserved05[10];1512 u8 aix;1513 u8 reserved06[4029];1514 struct chsc_header response;1515 u8 reserved07[4];1516 } *sgib_area;1517 int ret;1518 1519 spin_lock_irq(&chsc_page_lock);1520 memset(chsc_page, 0, PAGE_SIZE);1521 sgib_area = chsc_page;1522 sgib_area->request.length = 0x0fe0;1523 sgib_area->request.code = 0x0021;1524 sgib_area->op = 0x1;1525 sgib_area->gib_origin = origin;1526 1527 ret = chsc(sgib_area);1528 if (ret == 0)1529 ret = chsc_error_from_response(sgib_area->response.code);1530 spin_unlock_irq(&chsc_page_lock);1531 1532 return ret;1533}1534EXPORT_SYMBOL_GPL(chsc_sgib);1535 1536#define SCUD_REQ_LEN 0x10 /* SCUD request block length */1537#define SCUD_REQ_CMD 0x4b /* SCUD Command Code */1538 1539struct chse_cudb {1540 u16 flags:8;1541 u16 chp_valid:8;1542 u16 cu;1543 u32 esm_valid:8;1544 u32:24;1545 u8 chpid[8];1546 u32:32;1547 u32:32;1548 u8 esm[8];1549 u32 efla[8];1550} __packed;1551 1552struct chsc_scud {1553 struct chsc_header request;1554 u16:4;1555 u16 fmt:4;1556 u16 cssid:8;1557 u16 first_cu;1558 u16:16;1559 u16 last_cu;1560 u32:32;1561 struct chsc_header response;1562 u16:4;1563 u16 fmt_resp:4;1564 u32:24;1565 struct chse_cudb cudb[];1566} __packed;1567 1568/**1569 * chsc_scud() - Store control-unit description.1570 * @cu: number of the control-unit1571 * @esm: 8 1-byte endpoint security mode values1572 * @esm_valid: validity mask for @esm1573 *1574 * Interface to retrieve information about the endpoint security1575 * modes for up to 8 paths of a control unit.1576 *1577 * Returns 0 on success.1578 */1579int chsc_scud(u16 cu, u64 *esm, u8 *esm_valid)1580{1581 struct chsc_scud *scud = chsc_page;1582 int ret;1583 1584 spin_lock_irq(&chsc_page_lock);1585 memset(chsc_page, 0, PAGE_SIZE);1586 scud->request.length = SCUD_REQ_LEN;1587 scud->request.code = SCUD_REQ_CMD;1588 scud->fmt = 0;1589 scud->cssid = 0;1590 scud->first_cu = cu;1591 scud->last_cu = cu;1592 1593 ret = chsc(scud);1594 if (!ret)1595 ret = chsc_error_from_response(scud->response.code);1596 1597 if (!ret && (scud->response.length <= 8 || scud->fmt_resp != 01598 || !(scud->cudb[0].flags & 0x80)1599 || scud->cudb[0].cu != cu)) {1600 1601 CIO_MSG_EVENT(2, "chsc: scud failed rc=%04x, L2=%04x "1602 "FMT=%04x, cudb.flags=%02x, cudb.cu=%04x",1603 scud->response.code, scud->response.length,1604 scud->fmt_resp, scud->cudb[0].flags, scud->cudb[0].cu);1605 ret = -EINVAL;1606 }1607 1608 if (ret)1609 goto out;1610 1611 memcpy(esm, scud->cudb[0].esm, sizeof(*esm));1612 *esm_valid = scud->cudb[0].esm_valid;1613out:1614 spin_unlock_irq(&chsc_page_lock);1615 return ret;1616}1617EXPORT_SYMBOL_GPL(chsc_scud);1618