diff options
Diffstat (limited to 'drivers/s390/cio/chsc.c')
| -rw-r--r-- | drivers/s390/cio/chsc.c | 96 | 
1 files changed, 55 insertions, 41 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 13299f90267..e3bf885f4a6 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -55,6 +55,7 @@ int chsc_error_from_response(int response)  	case 0x0004:  		return -EOPNOTSUPP;  	case 0x000b: +	case 0x0107:		/* "Channel busy" for the op 0x003d */  		return -EBUSY;  	case 0x0100:  	case 0x0102: @@ -237,26 +238,6 @@ void chsc_chp_offline(struct chp_id chpid)  	for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link);  } -static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data) -{ -	struct schib schib; -	/* -	 * We don't know the device yet, but since a path -	 * may be available now to the device we'll have -	 * to do recognition again. -	 * Since we don't have any idea about which chpid -	 * that beast may be on we'll have to do a stsch -	 * on all devices, grr... -	 */ -	if (stsch_err(schid, &schib)) -		/* We're through */ -		return -ENXIO; - -	/* Put it on the slow path. */ -	css_schedule_eval(schid); -	return 0; -} -  static int __s390_process_res_acc(struct subchannel *sch, void *data)  {  	spin_lock_irq(sch->lock); @@ -287,8 +268,8 @@ static void s390_process_res_acc(struct chp_link *link)  	 * The more information we have (info), the less scanning  	 * will we have to do.  	 */ -	for_each_subchannel_staged(__s390_process_res_acc, -				   s390_process_res_acc_new_sch, link); +	for_each_subchannel_staged(__s390_process_res_acc, NULL, link); +	css_schedule_reprobe();  }  static int @@ -560,18 +541,27 @@ static void chsc_process_sei_nt0(struct chsc_sei_nt0_area *sei_area)  static void chsc_process_event_information(struct chsc_sei *sei, u64 ntsm)  { -	do { +	static int ntsm_unsupported; + +	while (true) {  		memset(sei, 0, sizeof(*sei));  		sei->request.length = 0x0010;  		sei->request.code = 0x000e; -		sei->ntsm = ntsm; +		if (!ntsm_unsupported) +			sei->ntsm = ntsm;  		if (chsc(sei))  			break;  		if (sei->response.code != 0x0001) { -			CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", -				      sei->response.code); +			CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x, ntsm=%llx)\n", +				      sei->response.code, sei->ntsm); + +			if (sei->response.code == 3 && sei->ntsm) { +				/* Fallback for old firmware. */ +				ntsm_unsupported = 1; +				continue; +			}  			break;  		} @@ -587,7 +577,10 @@ static void chsc_process_event_information(struct chsc_sei *sei, u64 ntsm)  			CIO_CRW_EVENT(2, "chsc: unhandled nt: %d\n", sei->nt);  			break;  		} -	} while (sei->u.nt0_area.flags & 0x80); + +		if (!(sei->u.nt0_area.flags & 0x80)) +			break; +	}  }  /* @@ -629,6 +622,7 @@ void chsc_chp_online(struct chp_id chpid)  		css_wait_for_slow_path();  		for_each_subchannel_staged(__s390_process_res_acc, NULL,  					   &link); +		css_schedule_reprobe();  	}  } @@ -663,19 +657,6 @@ static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data)  	return 0;  } -static int -__s390_vary_chpid_on(struct subchannel_id schid, void *data) -{ -	struct schib schib; - -	if (stsch_err(schid, &schib)) -		/* We're through */ -		return -ENXIO; -	/* Put it on the slow path. */ -	css_schedule_eval(schid); -	return 0; -} -  /**   * chsc_chp_vary - propagate channel-path vary operation to subchannels   * @chpid: channl-path ID @@ -694,7 +675,8 @@ int chsc_chp_vary(struct chp_id chpid, int on)  		/* Try to update the channel path description. */  		chp_update_desc(chp);  		for_each_subchannel_staged(s390_subchannel_vary_chpid_on, -					   __s390_vary_chpid_on, &chpid); +					   NULL, &chpid); +		css_schedule_reprobe();  	} else  		for_each_subchannel_staged(s390_subchannel_vary_chpid_off,  					   NULL, &chpid); @@ -1234,3 +1216,35 @@ out:  	return ret;  }  EXPORT_SYMBOL_GPL(chsc_scm_info); + +/** + * chsc_pnso_brinfo() - Perform Network-Subchannel Operation, Bridge Info. + * @schid:		id of the subchannel on which PNSO is performed + * @brinfo_area:	request and response block for the operation + * @resume_token:	resume token for multiblock response + * @cnc:		Boolean change-notification control + * + * brinfo_area must be allocated by the caller with get_zeroed_page(GFP_KERNEL) + * + * Returns 0 on success. + */ +int chsc_pnso_brinfo(struct subchannel_id schid, +		struct chsc_pnso_area *brinfo_area, +		struct chsc_brinfo_resume_token resume_token, +		int cnc) +{ +	memset(brinfo_area, 0, sizeof(*brinfo_area)); +	brinfo_area->request.length = 0x0030; +	brinfo_area->request.code = 0x003d; /* network-subchannel operation */ +	brinfo_area->m	   = schid.m; +	brinfo_area->ssid  = schid.ssid; +	brinfo_area->sch   = schid.sch_no; +	brinfo_area->cssid = schid.cssid; +	brinfo_area->oc    = 0; /* Store-network-bridging-information list */ +	brinfo_area->resume_token = resume_token; +	brinfo_area->n	   = (cnc != 0); +	if (chsc(brinfo_area)) +		return -EIO; +	return chsc_error_from_response(brinfo_area->response.code); +} +EXPORT_SYMBOL_GPL(chsc_pnso_brinfo);  | 
