diff options
| author | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
|---|---|---|
| committer | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
| commit | 5c34202b8bf942da411b6599668a76b07449bbfd (patch) | |
| tree | 5719c361321eaddc8e4f1b0c8a7994f0e9a6fdd3 /drivers/s390/net/qeth_main.c | |
| parent | 0d4804b31f91cfbcff6d62af0bc09a893a1c8ae0 (diff) | |
| parent | 1f8a6b658a943b4f04a1fc7b3a420360202c86cd (diff) | |
Merge /pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/s390/net/qeth_main.c')
| -rw-r--r-- | drivers/s390/net/qeth_main.c | 124 | 
1 files changed, 103 insertions, 21 deletions
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index ad7792dc1a0..0b96d49dd63 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -315,7 +315,8 @@ qeth_alloc_card(void)  }  static long -__qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb) +__qeth_check_irb_error(struct ccw_device *cdev, unsigned long intparm, +		       struct irb *irb)  {  	if (!IS_ERR(irb))  		return 0; @@ -330,6 +331,14 @@ __qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb)  		PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);  		QETH_DBF_TEXT(trace, 2, "ckirberr");  		QETH_DBF_TEXT_(trace, 2, "  rc%d", -ETIMEDOUT); +		if (intparm == QETH_RCD_PARM) { +			struct qeth_card *card = CARD_FROM_CDEV(cdev); + +			if (card && (card->data.ccwdev == cdev)) { +				card->data.state = CH_STATE_DOWN; +				wake_up(&card->wait_q); +			} +		}  		break;  	default:  		PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), @@ -401,7 +410,7 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)  	QETH_DBF_TEXT(trace,5,"irq"); -	if (__qeth_check_irb_error(cdev, irb)) +	if (__qeth_check_irb_error(cdev, intparm, irb))  		return;  	cstat = irb->scsw.cstat;  	dstat = irb->scsw.dstat; @@ -429,7 +438,8 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)  		channel->state = CH_STATE_HALTED;  	/*let's wake up immediately on data channel*/ -	if ((channel == &card->data) && (intparm != 0)) +	if ((channel == &card->data) && (intparm != 0) && +	    (intparm != QETH_RCD_PARM))  		goto out;  	if (intparm == QETH_CLEAR_CHANNEL_PARM) { @@ -453,6 +463,10 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)  			HEXDUMP16(WARN,"irb: ",irb);  			HEXDUMP16(WARN,"sense data: ",irb->ecw);  		} +		if (intparm == QETH_RCD_PARM) { +			channel->state = CH_STATE_DOWN; +			goto out; +		}  		rc = qeth_get_problem(cdev,irb);  		if (rc) {  			qeth_schedule_recovery(card); @@ -460,6 +474,10 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)  		}  	} +	if (intparm == QETH_RCD_PARM) { +		channel->state = CH_STATE_RCD_DONE; +		goto out; +	}  	if (intparm) {  		buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm);  		buffer->state = BUF_STATE_PROCESSED; @@ -1204,6 +1222,54 @@ qeth_probe_device(struct ccwgroup_device *gdev)  } +static int qeth_read_conf_data(struct qeth_card *card, void **buffer, +			       int *length) +{ +	struct ciw *ciw; +	char *rcd_buf; +	int ret; +	struct qeth_channel *channel = &card->data; +	unsigned long flags; + +	/* +	 * scan for RCD command in extended SenseID data +	 */ +	ciw = ccw_device_get_ciw(channel->ccwdev, CIW_TYPE_RCD); +	if (!ciw || ciw->cmd == 0) +		return -EOPNOTSUPP; +	rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA); +	if (!rcd_buf) +		return -ENOMEM; + +	channel->ccw.cmd_code = ciw->cmd; +	channel->ccw.cda = (__u32) __pa (rcd_buf); +	channel->ccw.count = ciw->count; +	channel->ccw.flags = CCW_FLAG_SLI; +	channel->state = CH_STATE_RCD; +	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); +	ret = ccw_device_start_timeout(channel->ccwdev, &channel->ccw, +				       QETH_RCD_PARM, LPM_ANYPATH, 0, +				       QETH_RCD_TIMEOUT); +	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); +	if (!ret) +		wait_event(card->wait_q, +			   (channel->state == CH_STATE_RCD_DONE || +			    channel->state == CH_STATE_DOWN)); +	if (channel->state == CH_STATE_DOWN) +		ret = -EIO; +	else +		channel->state = CH_STATE_DOWN; +	if (ret) { +		kfree(rcd_buf); +		*buffer = NULL; +		*length = 0; +	} else { +		*length = ciw->count; +		*buffer = rcd_buf; +	} +	return ret; +} +  static int  qeth_get_unitaddr(struct qeth_card *card)  { @@ -1212,9 +1278,9 @@ qeth_get_unitaddr(struct qeth_card *card)  	int rc;  	QETH_DBF_TEXT(setup, 2, "getunit"); -	rc = read_conf_data(CARD_DDEV(card), (void **) &prcd, &length); +	rc = qeth_read_conf_data(card, (void **) &prcd, &length);  	if (rc) { -		PRINT_ERR("read_conf_data for device %s returned %i\n", +		PRINT_ERR("qeth_read_conf_data for device %s returned %i\n",  			  CARD_DDEV_ID(card), rc);  		return rc;  	} @@ -1223,6 +1289,7 @@ qeth_get_unitaddr(struct qeth_card *card)  	card->info.cula = prcd[63];  	card->info.guestlan = ((prcd[0x10] == _ascebc['V']) &&  			       (prcd[0x11] == _ascebc['M'])); +	kfree(prcd);  	return 0;  } @@ -1615,6 +1682,21 @@ qeth_put_reply(struct qeth_reply *reply)  		kfree(reply);  } +static void +qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, struct qeth_card *card) +{ +	int rc; +	int com; +	char * ipa_name; + +	com = cmd->hdr.command; +	rc  = cmd->hdr.return_code; +	ipa_name = qeth_get_ipa_cmd_name(com); + +	PRINT_ERR("%s(x%X) for %s returned x%X \"%s\"\n", ipa_name, com, +		   QETH_CARD_IFNAME(card), rc, qeth_get_ipa_msg(rc)); +} +  static struct qeth_ipa_cmd *  qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)  { @@ -1623,8 +1705,11 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)  	QETH_DBF_TEXT(trace,5,"chkipad");  	if (IS_IPA(iob->data)){  		cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); -		if (IS_IPA_REPLY(cmd)) +		if (IS_IPA_REPLY(cmd)) { +			if (cmd->hdr.return_code) +				qeth_issue_ipa_msg(cmd, card);  			return cmd; +		}  		else {  			switch (cmd->hdr.command) {  			case IPA_CMD_STOPLAN: @@ -2749,6 +2834,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,  	struct qeth_qdio_out_buffer *buf;  	int rc;  	int i; +	unsigned int qdio_flags;  	QETH_DBF_TEXT(trace, 6, "flushbuf"); @@ -2774,7 +2860,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,  			if (!atomic_read(&queue->set_pci_flags_count)){  				/*  				 * there's no outstanding PCI any more, so we -				 * have to request a PCI to be sure the the PCI +				 * have to request a PCI to be sure that the PCI  				 * will wake at some time in the future then we  				 * can flush packed buffers that might still be  				 * hanging around, which can happen if no @@ -2792,13 +2878,13 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,  		queue->card->perf_stats.outbound_do_qdio_start_time =  			qeth_get_micros();  	} +	qdio_flags = QDIO_FLAG_SYNC_OUTPUT;  	if (under_int) -		rc = do_QDIO(CARD_DDEV(queue->card), -			     QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT, -			     queue->queue_no, index, count, NULL); -	else -		rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT, -			     queue->queue_no, index, count, NULL); +		qdio_flags |= QDIO_FLAG_UNDER_INTERRUPT; +	if (atomic_read(&queue->set_pci_flags_count)) +		qdio_flags |= QDIO_FLAG_PCI_OUT; +	rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags, +		     queue->queue_no, index, count, NULL);  	if (queue->card->options.performance_stats)  		queue->card->perf_stats.outbound_do_qdio_time +=  			qeth_get_micros() - @@ -4423,7 +4509,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)  		qeth_fill_header(card, hdr, new_skb, ipv, cast_type);  	}  	if (large_send == QETH_LARGE_SEND_EDDP) { -		ctx = qeth_eddp_create_context(card, new_skb, hdr); +		ctx = qeth_eddp_create_context(card, new_skb, hdr, +					       skb->sk->sk_protocol);  		if (ctx == NULL) {  			__qeth_free_new_skb(skb, new_skb);  			PRINT_WARN("could not create eddp context\n"); @@ -5881,9 +5968,6 @@ qeth_layer2_send_setmac_cb(struct qeth_card *card,  	cmd = (struct qeth_ipa_cmd *) data;  	if (cmd->hdr.return_code) {  		QETH_DBF_TEXT_(trace, 2, "L2er%x", cmd->hdr.return_code); -		PRINT_WARN("Error in registering MAC address on " \ -			   "device %s: x%x\n", CARD_BUS_ID(card), -			   cmd->hdr.return_code);  		card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;  		cmd->hdr.return_code = -EIO;  	} else { @@ -5918,9 +6002,6 @@ qeth_layer2_send_delmac_cb(struct qeth_card *card,  	QETH_DBF_TEXT(trace, 2, "L2Dmaccb");  	cmd = (struct qeth_ipa_cmd *) data;  	if (cmd->hdr.return_code) { -		PRINT_WARN("Error in deregistering MAC address on " \ -			   "device %s: x%x\n", CARD_BUS_ID(card), -			   cmd->hdr.return_code);  		QETH_DBF_TEXT_(trace, 2, "err%d", cmd->hdr.return_code);  		cmd->hdr.return_code = -EIO;  		return 0; @@ -6584,7 +6665,7 @@ qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,  	QETH_DBF_TEXT(trace,4,"chgmaccb");  	cmd = (struct qeth_ipa_cmd *) data; -	if (!card->options.layer2 || card->info.guestlan || +	if (!card->options.layer2 ||  	    !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {  		memcpy(card->dev->dev_addr,  		       &cmd->data.setadapterparms.data.change_addr.addr, @@ -8430,6 +8511,7 @@ __qeth_reboot_event_card(struct device *dev, void *data)  	card = (struct qeth_card *) dev->driver_data;  	qeth_clear_ip_list(card, 0, 0);  	qeth_qdio_clear_card(card, 0); +	qeth_clear_qdio_buffers(card);  	return 0;  }  | 
