| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame^] | 1 | /* | 
 | 2 |  * driver/s390/cio/qdio_setup.c | 
 | 3 |  * | 
 | 4 |  * qdio queue initialization | 
 | 5 |  * | 
 | 6 |  * Copyright (C) IBM Corp. 2008 | 
 | 7 |  * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> | 
 | 8 |  */ | 
 | 9 | #include <linux/kernel.h> | 
 | 10 | #include <linux/slab.h> | 
 | 11 | #include <asm/qdio.h> | 
 | 12 |  | 
 | 13 | #include "cio.h" | 
 | 14 | #include "css.h" | 
 | 15 | #include "device.h" | 
 | 16 | #include "ioasm.h" | 
 | 17 | #include "chsc.h" | 
 | 18 | #include "qdio.h" | 
 | 19 | #include "qdio_debug.h" | 
 | 20 |  | 
 | 21 | static struct kmem_cache *qdio_q_cache; | 
 | 22 |  | 
 | 23 | /* | 
 | 24 |  * qebsm is only available under 64bit but the adapter sets the feature | 
 | 25 |  * flag anyway, so we manually override it. | 
 | 26 |  */ | 
 | 27 | static inline int qebsm_possible(void) | 
 | 28 | { | 
 | 29 | #ifdef CONFIG_64BIT | 
 | 30 | 	return css_general_characteristics.qebsm; | 
 | 31 | #endif | 
 | 32 | 	return 0; | 
 | 33 | } | 
 | 34 |  | 
 | 35 | /* | 
 | 36 |  * qib_param_field: pointer to 128 bytes or NULL, if no param field | 
 | 37 |  * nr_input_qs: pointer to nr_queues*128 words of data or NULL | 
 | 38 |  */ | 
 | 39 | static void set_impl_params(struct qdio_irq *irq_ptr, | 
 | 40 | 			    unsigned int qib_param_field_format, | 
 | 41 | 			    unsigned char *qib_param_field, | 
 | 42 | 			    unsigned long *input_slib_elements, | 
 | 43 | 			    unsigned long *output_slib_elements) | 
 | 44 | { | 
 | 45 | 	struct qdio_q *q; | 
 | 46 | 	int i, j; | 
 | 47 |  | 
 | 48 | 	if (!irq_ptr) | 
 | 49 | 		return; | 
 | 50 |  | 
 | 51 | 	WARN_ON((unsigned long)&irq_ptr->qib & 0xff); | 
 | 52 | 	irq_ptr->qib.pfmt = qib_param_field_format; | 
 | 53 | 	if (qib_param_field) | 
 | 54 | 		memcpy(irq_ptr->qib.parm, qib_param_field, | 
 | 55 | 		       QDIO_MAX_BUFFERS_PER_Q); | 
 | 56 |  | 
 | 57 | 	if (!input_slib_elements) | 
 | 58 | 		goto output; | 
 | 59 |  | 
 | 60 | 	for_each_input_queue(irq_ptr, q, i) { | 
 | 61 | 		for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) | 
 | 62 | 			q->slib->slibe[j].parms = | 
 | 63 | 				input_slib_elements[i * QDIO_MAX_BUFFERS_PER_Q + j]; | 
 | 64 | 	} | 
 | 65 | output: | 
 | 66 | 	if (!output_slib_elements) | 
 | 67 | 		return; | 
 | 68 |  | 
 | 69 | 	for_each_output_queue(irq_ptr, q, i) { | 
 | 70 | 		for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) | 
 | 71 | 			q->slib->slibe[j].parms = | 
 | 72 | 				output_slib_elements[i * QDIO_MAX_BUFFERS_PER_Q + j]; | 
 | 73 | 	} | 
 | 74 | } | 
 | 75 |  | 
 | 76 | static int __qdio_allocate_qs(struct qdio_q **irq_ptr_qs, int nr_queues) | 
 | 77 | { | 
 | 78 | 	struct qdio_q *q; | 
 | 79 | 	int i; | 
 | 80 |  | 
 | 81 | 	for (i = 0; i < nr_queues; i++) { | 
 | 82 | 		q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL); | 
 | 83 | 		if (!q) | 
 | 84 | 			return -ENOMEM; | 
 | 85 | 		WARN_ON((unsigned long)q & 0xff); | 
 | 86 |  | 
 | 87 | 		q->slib = (struct slib *) __get_free_page(GFP_KERNEL); | 
 | 88 | 		if (!q->slib) { | 
 | 89 | 			kmem_cache_free(qdio_q_cache, q); | 
 | 90 | 			return -ENOMEM; | 
 | 91 | 		} | 
 | 92 | 		WARN_ON((unsigned long)q->slib & 0x7ff); | 
 | 93 | 		irq_ptr_qs[i] = q; | 
 | 94 | 	} | 
 | 95 | 	return 0; | 
 | 96 | } | 
 | 97 |  | 
 | 98 | int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, int nr_output_qs) | 
 | 99 | { | 
 | 100 | 	int rc; | 
 | 101 |  | 
 | 102 | 	rc = __qdio_allocate_qs(irq_ptr->input_qs, nr_input_qs); | 
 | 103 | 	if (rc) | 
 | 104 | 		return rc; | 
 | 105 | 	rc = __qdio_allocate_qs(irq_ptr->output_qs, nr_output_qs); | 
 | 106 | 	return rc; | 
 | 107 | } | 
 | 108 |  | 
 | 109 | static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr, | 
 | 110 | 			      qdio_handler_t *handler, int i) | 
 | 111 | { | 
 | 112 | 	/* must be cleared by every qdio_establish */ | 
 | 113 | 	memset(q, 0, ((char *)&q->slib) - ((char *)q)); | 
 | 114 | 	memset(q->slib, 0, PAGE_SIZE); | 
 | 115 |  | 
 | 116 | 	q->irq_ptr = irq_ptr; | 
 | 117 | 	q->mask = 1 << (31 - i); | 
 | 118 | 	q->nr = i; | 
 | 119 | 	q->handler = handler; | 
 | 120 | } | 
 | 121 |  | 
 | 122 | static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, | 
 | 123 | 				void **sbals_array, char *dbf_text, int i) | 
 | 124 | { | 
 | 125 | 	struct qdio_q *prev; | 
 | 126 | 	int j; | 
 | 127 |  | 
 | 128 | 	QDIO_DBF_TEXT0(0, setup, dbf_text); | 
 | 129 | 	QDIO_DBF_HEX0(0, setup, &q, sizeof(void *)); | 
 | 130 |  | 
 | 131 | 	q->sl = (struct sl *)((char *)q->slib + PAGE_SIZE / 2); | 
 | 132 |  | 
 | 133 | 	/* fill in sbal */ | 
 | 134 | 	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) { | 
 | 135 | 		q->sbal[j] = *sbals_array++; | 
 | 136 | 		WARN_ON((unsigned long)q->sbal[j] & 0xff); | 
 | 137 | 	} | 
 | 138 |  | 
 | 139 | 	/* fill in slib */ | 
 | 140 | 	if (i > 0) { | 
 | 141 | 		prev = (q->is_input_q) ? irq_ptr->input_qs[i - 1] | 
 | 142 | 			: irq_ptr->output_qs[i - 1]; | 
 | 143 | 		prev->slib->nsliba = (unsigned long)q->slib; | 
 | 144 | 	} | 
 | 145 |  | 
 | 146 | 	q->slib->sla = (unsigned long)q->sl; | 
 | 147 | 	q->slib->slsba = (unsigned long)&q->slsb.val[0]; | 
 | 148 |  | 
 | 149 | 	/* fill in sl */ | 
 | 150 | 	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) | 
 | 151 | 		q->sl->element[j].sbal = (unsigned long)q->sbal[j]; | 
 | 152 |  | 
 | 153 | 	QDIO_DBF_TEXT2(0, setup, "sl-sb-b0"); | 
 | 154 | 	QDIO_DBF_HEX2(0, setup, q->sl, sizeof(void *)); | 
 | 155 | 	QDIO_DBF_HEX2(0, setup, &q->slsb, sizeof(void *)); | 
 | 156 | 	QDIO_DBF_HEX2(0, setup, q->sbal, sizeof(void *)); | 
 | 157 | } | 
 | 158 |  | 
 | 159 | static void setup_queues(struct qdio_irq *irq_ptr, | 
 | 160 | 			 struct qdio_initialize *qdio_init) | 
 | 161 | { | 
 | 162 | 	char dbf_text[20]; | 
 | 163 | 	struct qdio_q *q; | 
 | 164 | 	void **input_sbal_array = qdio_init->input_sbal_addr_array; | 
 | 165 | 	void **output_sbal_array = qdio_init->output_sbal_addr_array; | 
 | 166 | 	int i; | 
 | 167 |  | 
 | 168 | 	sprintf(dbf_text, "qfqs%4x", qdio_init->cdev->private->schid.sch_no); | 
 | 169 | 	QDIO_DBF_TEXT0(0, setup, dbf_text); | 
 | 170 |  | 
 | 171 | 	for_each_input_queue(irq_ptr, q, i) { | 
 | 172 | 		sprintf(dbf_text, "in-q%4x", i); | 
 | 173 | 		setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); | 
 | 174 |  | 
 | 175 | 		q->is_input_q = 1; | 
 | 176 | 		spin_lock_init(&q->u.in.lock); | 
 | 177 | 		setup_storage_lists(q, irq_ptr, input_sbal_array, dbf_text, i); | 
 | 178 | 		input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; | 
 | 179 |  | 
 | 180 | 		if (is_thinint_irq(irq_ptr)) | 
 | 181 | 			tasklet_init(&q->tasklet, tiqdio_inbound_processing, | 
 | 182 | 				     (unsigned long) q); | 
 | 183 | 		else | 
 | 184 | 			tasklet_init(&q->tasklet, qdio_inbound_processing, | 
 | 185 | 				     (unsigned long) q); | 
 | 186 | 	} | 
 | 187 |  | 
 | 188 | 	for_each_output_queue(irq_ptr, q, i) { | 
 | 189 | 		sprintf(dbf_text, "outq%4x", i); | 
 | 190 | 		setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i); | 
 | 191 |  | 
 | 192 | 		q->is_input_q = 0; | 
 | 193 | 		setup_storage_lists(q, irq_ptr, output_sbal_array, | 
 | 194 | 				    dbf_text, i); | 
 | 195 | 		output_sbal_array += QDIO_MAX_BUFFERS_PER_Q; | 
 | 196 |  | 
 | 197 | 		tasklet_init(&q->tasklet, qdio_outbound_processing, | 
 | 198 | 			     (unsigned long) q); | 
 | 199 | 		setup_timer(&q->u.out.timer, (void(*)(unsigned long)) | 
 | 200 | 			    &qdio_outbound_timer, (unsigned long)q); | 
 | 201 | 	} | 
 | 202 | } | 
 | 203 |  | 
 | 204 | static void process_ac_flags(struct qdio_irq *irq_ptr, unsigned char qdioac) | 
 | 205 | { | 
 | 206 | 	if (qdioac & AC1_SIGA_INPUT_NEEDED) | 
 | 207 | 		irq_ptr->siga_flag.input = 1; | 
 | 208 | 	if (qdioac & AC1_SIGA_OUTPUT_NEEDED) | 
 | 209 | 		irq_ptr->siga_flag.output = 1; | 
 | 210 | 	if (qdioac & AC1_SIGA_SYNC_NEEDED) | 
 | 211 | 		irq_ptr->siga_flag.sync = 1; | 
 | 212 | 	if (qdioac & AC1_AUTOMATIC_SYNC_ON_THININT) | 
 | 213 | 		irq_ptr->siga_flag.no_sync_ti = 1; | 
 | 214 | 	if (qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI) | 
 | 215 | 		irq_ptr->siga_flag.no_sync_out_pci = 1; | 
 | 216 |  | 
 | 217 | 	if (irq_ptr->siga_flag.no_sync_out_pci && | 
 | 218 | 	    irq_ptr->siga_flag.no_sync_ti) | 
 | 219 | 		irq_ptr->siga_flag.no_sync_out_ti = 1; | 
 | 220 | } | 
 | 221 |  | 
 | 222 | static void check_and_setup_qebsm(struct qdio_irq *irq_ptr, | 
 | 223 | 				  unsigned char qdioac, unsigned long token) | 
 | 224 | { | 
 | 225 | 	char dbf_text[15]; | 
 | 226 |  | 
 | 227 | 	if (!(irq_ptr->qib.rflags & QIB_RFLAGS_ENABLE_QEBSM)) | 
 | 228 | 		goto no_qebsm; | 
 | 229 | 	if (!(qdioac & AC1_SC_QEBSM_AVAILABLE) || | 
 | 230 | 	    (!(qdioac & AC1_SC_QEBSM_ENABLED))) | 
 | 231 | 		goto no_qebsm; | 
 | 232 |  | 
 | 233 | 	irq_ptr->sch_token = token; | 
 | 234 |  | 
 | 235 | 	QDIO_DBF_TEXT0(0, setup, "V=V:1"); | 
 | 236 | 	sprintf(dbf_text, "%8lx", irq_ptr->sch_token); | 
 | 237 | 	QDIO_DBF_TEXT0(0, setup, dbf_text); | 
 | 238 | 	return; | 
 | 239 |  | 
 | 240 | no_qebsm: | 
 | 241 | 	irq_ptr->sch_token = 0; | 
 | 242 | 	irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; | 
 | 243 | 	QDIO_DBF_TEXT0(0, setup, "noV=V"); | 
 | 244 | } | 
 | 245 |  | 
 | 246 | static int __get_ssqd_info(struct qdio_irq *irq_ptr) | 
 | 247 | { | 
 | 248 | 	struct chsc_ssqd_area *ssqd; | 
 | 249 | 	int rc; | 
 | 250 |  | 
 | 251 | 	QDIO_DBF_TEXT0(0, setup, "getssqd"); | 
 | 252 | 	ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; | 
 | 253 | 	memset(ssqd, 0, PAGE_SIZE); | 
 | 254 |  | 
 | 255 | 	ssqd->request = (struct chsc_header) { | 
 | 256 | 		.length = 0x0010, | 
 | 257 | 		.code	= 0x0024, | 
 | 258 | 	}; | 
 | 259 | 	ssqd->first_sch = irq_ptr->schid.sch_no; | 
 | 260 | 	ssqd->last_sch = irq_ptr->schid.sch_no; | 
 | 261 | 	ssqd->ssid = irq_ptr->schid.ssid; | 
 | 262 |  | 
 | 263 | 	if (chsc(ssqd)) | 
 | 264 | 		return -EIO; | 
 | 265 | 	rc = chsc_error_from_response(ssqd->response.code); | 
 | 266 | 	if (rc) | 
 | 267 | 		return rc; | 
 | 268 |  | 
 | 269 | 	if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || | 
 | 270 | 	    !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || | 
 | 271 | 	    (ssqd->qdio_ssqd.sch != irq_ptr->schid.sch_no)) | 
 | 272 | 		return -EINVAL; | 
 | 273 |  | 
 | 274 | 	memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, | 
 | 275 | 	       sizeof(struct qdio_ssqd_desc)); | 
 | 276 | 	return 0; | 
 | 277 | } | 
 | 278 |  | 
 | 279 | void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) | 
 | 280 | { | 
 | 281 | 	unsigned char qdioac; | 
 | 282 | 	char dbf_text[15]; | 
 | 283 | 	int rc; | 
 | 284 |  | 
 | 285 | 	rc = __get_ssqd_info(irq_ptr); | 
 | 286 | 	if (rc) { | 
 | 287 | 		QDIO_DBF_TEXT2(0, setup, "ssqdasig"); | 
 | 288 | 		sprintf(dbf_text, "schno%x", irq_ptr->schid.sch_no); | 
 | 289 | 		QDIO_DBF_TEXT2(0, setup, dbf_text); | 
 | 290 | 		sprintf(dbf_text, "rc:%d", rc); | 
 | 291 | 		QDIO_DBF_TEXT2(0, setup, dbf_text); | 
 | 292 | 		/* all flags set, worst case */ | 
 | 293 | 		qdioac = AC1_SIGA_INPUT_NEEDED | AC1_SIGA_OUTPUT_NEEDED | | 
 | 294 | 			 AC1_SIGA_SYNC_NEEDED; | 
 | 295 | 	} else | 
 | 296 | 		qdioac = irq_ptr->ssqd_desc.qdioac1; | 
 | 297 |  | 
 | 298 | 	check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token); | 
 | 299 | 	process_ac_flags(irq_ptr, qdioac); | 
 | 300 |  | 
 | 301 | 	sprintf(dbf_text, "qdioac%2x", qdioac); | 
 | 302 | 	QDIO_DBF_TEXT2(0, setup, dbf_text); | 
 | 303 | } | 
 | 304 |  | 
 | 305 | void qdio_release_memory(struct qdio_irq *irq_ptr) | 
 | 306 | { | 
 | 307 | 	struct qdio_q *q; | 
 | 308 | 	int i; | 
 | 309 |  | 
 | 310 | 	/* | 
 | 311 | 	 * Must check queue array manually since irq_ptr->nr_input_queues / | 
 | 312 | 	 * irq_ptr->nr_input_queues may not yet be set. | 
 | 313 | 	 */ | 
 | 314 | 	for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) { | 
 | 315 | 		q = irq_ptr->input_qs[i]; | 
 | 316 | 		if (q) { | 
 | 317 | 			free_page((unsigned long) q->slib); | 
 | 318 | 			kmem_cache_free(qdio_q_cache, q); | 
 | 319 | 		} | 
 | 320 | 	} | 
 | 321 | 	for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) { | 
 | 322 | 		q = irq_ptr->output_qs[i]; | 
 | 323 | 		if (q) { | 
 | 324 | 			free_page((unsigned long) q->slib); | 
 | 325 | 			kmem_cache_free(qdio_q_cache, q); | 
 | 326 | 		} | 
 | 327 | 	} | 
 | 328 | 	kfree(irq_ptr->qdr); | 
 | 329 | 	free_page(irq_ptr->chsc_page); | 
 | 330 | 	free_page((unsigned long) irq_ptr); | 
 | 331 | } | 
 | 332 |  | 
 | 333 | static void __qdio_allocate_fill_qdr(struct qdio_irq *irq_ptr, | 
 | 334 | 				     struct qdio_q **irq_ptr_qs, | 
 | 335 | 				     int i, int nr) | 
 | 336 | { | 
 | 337 | 	irq_ptr->qdr->qdf0[i + nr].sliba = | 
 | 338 | 		(unsigned long)irq_ptr_qs[i]->slib; | 
 | 339 |  | 
 | 340 | 	irq_ptr->qdr->qdf0[i + nr].sla = | 
 | 341 | 		(unsigned long)irq_ptr_qs[i]->sl; | 
 | 342 |  | 
 | 343 | 	irq_ptr->qdr->qdf0[i + nr].slsba = | 
 | 344 | 		(unsigned long)&irq_ptr_qs[i]->slsb.val[0]; | 
 | 345 |  | 
 | 346 | 	irq_ptr->qdr->qdf0[i + nr].akey = PAGE_DEFAULT_KEY; | 
 | 347 | 	irq_ptr->qdr->qdf0[i + nr].bkey = PAGE_DEFAULT_KEY; | 
 | 348 | 	irq_ptr->qdr->qdf0[i + nr].ckey = PAGE_DEFAULT_KEY; | 
 | 349 | 	irq_ptr->qdr->qdf0[i + nr].dkey = PAGE_DEFAULT_KEY; | 
 | 350 | } | 
 | 351 |  | 
 | 352 | static void setup_qdr(struct qdio_irq *irq_ptr, | 
 | 353 | 		      struct qdio_initialize *qdio_init) | 
 | 354 | { | 
 | 355 | 	int i; | 
 | 356 |  | 
 | 357 | 	irq_ptr->qdr->qfmt = qdio_init->q_format; | 
 | 358 | 	irq_ptr->qdr->iqdcnt = qdio_init->no_input_qs; | 
 | 359 | 	irq_ptr->qdr->oqdcnt = qdio_init->no_output_qs; | 
 | 360 | 	irq_ptr->qdr->iqdsz = sizeof(struct qdesfmt0) / 4; /* size in words */ | 
 | 361 | 	irq_ptr->qdr->oqdsz = sizeof(struct qdesfmt0) / 4; | 
 | 362 | 	irq_ptr->qdr->qiba = (unsigned long)&irq_ptr->qib; | 
 | 363 | 	irq_ptr->qdr->qkey = PAGE_DEFAULT_KEY; | 
 | 364 |  | 
 | 365 | 	for (i = 0; i < qdio_init->no_input_qs; i++) | 
 | 366 | 		__qdio_allocate_fill_qdr(irq_ptr, irq_ptr->input_qs, i, 0); | 
 | 367 |  | 
 | 368 | 	for (i = 0; i < qdio_init->no_output_qs; i++) | 
 | 369 | 		__qdio_allocate_fill_qdr(irq_ptr, irq_ptr->output_qs, i, | 
 | 370 | 					 qdio_init->no_input_qs); | 
 | 371 | } | 
 | 372 |  | 
 | 373 | static void setup_qib(struct qdio_irq *irq_ptr, | 
 | 374 | 		      struct qdio_initialize *init_data) | 
 | 375 | { | 
 | 376 | 	if (qebsm_possible()) | 
 | 377 | 		irq_ptr->qib.rflags |= QIB_RFLAGS_ENABLE_QEBSM; | 
 | 378 |  | 
 | 379 | 	irq_ptr->qib.qfmt = init_data->q_format; | 
 | 380 | 	if (init_data->no_input_qs) | 
 | 381 | 		irq_ptr->qib.isliba = | 
 | 382 | 			(unsigned long)(irq_ptr->input_qs[0]->slib); | 
 | 383 | 	if (init_data->no_output_qs) | 
 | 384 | 		irq_ptr->qib.osliba = | 
 | 385 | 			(unsigned long)(irq_ptr->output_qs[0]->slib); | 
 | 386 | 	memcpy(irq_ptr->qib.ebcnam, init_data->adapter_name, 8); | 
 | 387 | } | 
 | 388 |  | 
 | 389 | int qdio_setup_irq(struct qdio_initialize *init_data) | 
 | 390 | { | 
 | 391 | 	struct ciw *ciw; | 
 | 392 | 	struct qdio_irq *irq_ptr = init_data->cdev->private->qdio_data; | 
 | 393 | 	int rc; | 
 | 394 |  | 
 | 395 | 	memset(irq_ptr, 0, ((char *)&irq_ptr->qdr) - ((char *)irq_ptr)); | 
 | 396 | 	/* wipes qib.ac, required by ar7063 */ | 
 | 397 | 	memset(irq_ptr->qdr, 0, sizeof(struct qdr)); | 
 | 398 |  | 
 | 399 | 	irq_ptr->int_parm = init_data->int_parm; | 
 | 400 | 	irq_ptr->nr_input_qs = init_data->no_input_qs; | 
 | 401 | 	irq_ptr->nr_output_qs = init_data->no_output_qs; | 
 | 402 |  | 
 | 403 | 	irq_ptr->schid = ccw_device_get_subchannel_id(init_data->cdev); | 
 | 404 | 	irq_ptr->cdev = init_data->cdev; | 
 | 405 | 	setup_queues(irq_ptr, init_data); | 
 | 406 |  | 
 | 407 | 	setup_qib(irq_ptr, init_data); | 
 | 408 | 	qdio_setup_thinint(irq_ptr); | 
 | 409 | 	set_impl_params(irq_ptr, init_data->qib_param_field_format, | 
 | 410 | 			init_data->qib_param_field, | 
 | 411 | 			init_data->input_slib_elements, | 
 | 412 | 			init_data->output_slib_elements); | 
 | 413 |  | 
 | 414 | 	/* fill input and output descriptors */ | 
 | 415 | 	setup_qdr(irq_ptr, init_data); | 
 | 416 |  | 
 | 417 | 	/* qdr, qib, sls, slsbs, slibs, sbales are filled now */ | 
 | 418 |  | 
 | 419 | 	/* get qdio commands */ | 
 | 420 | 	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE); | 
 | 421 | 	if (!ciw) { | 
 | 422 | 		QDIO_DBF_TEXT2(1, setup, "no eq"); | 
 | 423 | 		rc = -EINVAL; | 
 | 424 | 		goto out_err; | 
 | 425 | 	} | 
 | 426 | 	irq_ptr->equeue = *ciw; | 
 | 427 |  | 
 | 428 | 	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE); | 
 | 429 | 	if (!ciw) { | 
 | 430 | 		QDIO_DBF_TEXT2(1, setup, "no aq"); | 
 | 431 | 		rc = -EINVAL; | 
 | 432 | 		goto out_err; | 
 | 433 | 	} | 
 | 434 | 	irq_ptr->aqueue = *ciw; | 
 | 435 |  | 
 | 436 | 	/* set new interrupt handler */ | 
 | 437 | 	irq_ptr->orig_handler = init_data->cdev->handler; | 
 | 438 | 	init_data->cdev->handler = qdio_int_handler; | 
 | 439 | 	return 0; | 
 | 440 | out_err: | 
 | 441 | 	qdio_release_memory(irq_ptr); | 
 | 442 | 	return rc; | 
 | 443 | } | 
 | 444 |  | 
 | 445 | void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, | 
 | 446 | 				struct ccw_device *cdev) | 
 | 447 | { | 
 | 448 | 	char s[80]; | 
 | 449 |  | 
 | 450 | 	sprintf(s, "%s ", cdev->dev.bus_id); | 
 | 451 |  | 
 | 452 | 	switch (irq_ptr->qib.qfmt) { | 
 | 453 | 	case QDIO_QETH_QFMT: | 
 | 454 | 		sprintf(s + strlen(s), "OSADE "); | 
 | 455 | 		break; | 
 | 456 | 	case QDIO_ZFCP_QFMT: | 
 | 457 | 		sprintf(s + strlen(s), "ZFCP "); | 
 | 458 | 		break; | 
 | 459 | 	case QDIO_IQDIO_QFMT: | 
 | 460 | 		sprintf(s + strlen(s), "HiperSockets "); | 
 | 461 | 		break; | 
 | 462 | 	} | 
 | 463 | 	sprintf(s + strlen(s), "using: "); | 
 | 464 |  | 
 | 465 | 	if (!is_thinint_irq(irq_ptr)) | 
 | 466 | 		sprintf(s + strlen(s), "no"); | 
 | 467 | 	sprintf(s + strlen(s), "AdapterInterrupts "); | 
 | 468 | 	if (!(irq_ptr->sch_token != 0)) | 
 | 469 | 		sprintf(s + strlen(s), "no"); | 
 | 470 | 	sprintf(s + strlen(s), "QEBSM "); | 
 | 471 | 	if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED)) | 
 | 472 | 		sprintf(s + strlen(s), "no"); | 
 | 473 | 	sprintf(s + strlen(s), "OutboundPCI "); | 
 | 474 | 	if (!css_general_characteristics.aif_tdd) | 
 | 475 | 		sprintf(s + strlen(s), "no"); | 
 | 476 | 	sprintf(s + strlen(s), "TDD\n"); | 
 | 477 | 	printk(KERN_INFO "qdio: %s", s); | 
 | 478 |  | 
 | 479 | 	memset(s, 0, sizeof(s)); | 
 | 480 | 	sprintf(s, "%s SIGA required: ", cdev->dev.bus_id); | 
 | 481 | 	if (irq_ptr->siga_flag.input) | 
 | 482 | 		sprintf(s + strlen(s), "Read "); | 
 | 483 | 	if (irq_ptr->siga_flag.output) | 
 | 484 | 		sprintf(s + strlen(s), "Write "); | 
 | 485 | 	if (irq_ptr->siga_flag.sync) | 
 | 486 | 		sprintf(s + strlen(s), "Sync "); | 
 | 487 | 	if (!irq_ptr->siga_flag.no_sync_ti) | 
 | 488 | 		sprintf(s + strlen(s), "SyncAI "); | 
 | 489 | 	if (!irq_ptr->siga_flag.no_sync_out_ti) | 
 | 490 | 		sprintf(s + strlen(s), "SyncOutAI "); | 
 | 491 | 	if (!irq_ptr->siga_flag.no_sync_out_pci) | 
 | 492 | 		sprintf(s + strlen(s), "SyncOutPCI"); | 
 | 493 | 	sprintf(s + strlen(s), "\n"); | 
 | 494 | 	printk(KERN_INFO "qdio: %s", s); | 
 | 495 | } | 
 | 496 |  | 
 | 497 | int __init qdio_setup_init(void) | 
 | 498 | { | 
 | 499 | 	char dbf_text[15]; | 
 | 500 |  | 
 | 501 | 	qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q), | 
 | 502 | 					 256, 0, NULL); | 
 | 503 | 	if (!qdio_q_cache) | 
 | 504 | 		return -ENOMEM; | 
 | 505 |  | 
 | 506 | 	/* Check for OSA/FCP thin interrupts (bit 67). */ | 
 | 507 | 	sprintf(dbf_text, "thini%1x", | 
 | 508 | 		(css_general_characteristics.aif_osa) ? 1 : 0); | 
 | 509 | 	QDIO_DBF_TEXT0(0, setup, dbf_text); | 
 | 510 |  | 
 | 511 | 	/* Check for QEBSM support in general (bit 58). */ | 
 | 512 | 	sprintf(dbf_text, "cssQBS:%1x", | 
 | 513 | 		(qebsm_possible()) ? 1 : 0); | 
 | 514 | 	QDIO_DBF_TEXT0(0, setup, dbf_text); | 
 | 515 | 	return 0; | 
 | 516 | } | 
 | 517 |  | 
 | 518 | void __exit qdio_setup_exit(void) | 
 | 519 | { | 
 | 520 | 	kmem_cache_destroy(qdio_q_cache); | 
 | 521 | } |