aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/net/qeth_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/net/qeth_main.c')
-rw-r--r--drivers/s390/net/qeth_main.c77
1 files changed, 72 insertions, 5 deletions
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index ad7792dc1a04..6fd8870551d3 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -315,7 +315,8 @@ qeth_alloc_card(void)
315} 315}
316 316
317static long 317static long
318__qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb) 318__qeth_check_irb_error(struct ccw_device *cdev, unsigned long intparm,
319 struct irb *irb)
319{ 320{
320 if (!IS_ERR(irb)) 321 if (!IS_ERR(irb))
321 return 0; 322 return 0;
@@ -330,6 +331,14 @@ __qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb)
330 PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id); 331 PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
331 QETH_DBF_TEXT(trace, 2, "ckirberr"); 332 QETH_DBF_TEXT(trace, 2, "ckirberr");
332 QETH_DBF_TEXT_(trace, 2, " rc%d", -ETIMEDOUT); 333 QETH_DBF_TEXT_(trace, 2, " rc%d", -ETIMEDOUT);
334 if (intparm == QETH_RCD_PARM) {
335 struct qeth_card *card = CARD_FROM_CDEV(cdev);
336
337 if (card && (card->data.ccwdev == cdev)) {
338 card->data.state = CH_STATE_DOWN;
339 wake_up(&card->wait_q);
340 }
341 }
333 break; 342 break;
334 default: 343 default:
335 PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), 344 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)
401 410
402 QETH_DBF_TEXT(trace,5,"irq"); 411 QETH_DBF_TEXT(trace,5,"irq");
403 412
404 if (__qeth_check_irb_error(cdev, irb)) 413 if (__qeth_check_irb_error(cdev, intparm, irb))
405 return; 414 return;
406 cstat = irb->scsw.cstat; 415 cstat = irb->scsw.cstat;
407 dstat = irb->scsw.dstat; 416 dstat = irb->scsw.dstat;
@@ -429,7 +438,8 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
429 channel->state = CH_STATE_HALTED; 438 channel->state = CH_STATE_HALTED;
430 439
431 /*let's wake up immediately on data channel*/ 440 /*let's wake up immediately on data channel*/
432 if ((channel == &card->data) && (intparm != 0)) 441 if ((channel == &card->data) && (intparm != 0) &&
442 (intparm != QETH_RCD_PARM))
433 goto out; 443 goto out;
434 444
435 if (intparm == QETH_CLEAR_CHANNEL_PARM) { 445 if (intparm == QETH_CLEAR_CHANNEL_PARM) {
@@ -453,6 +463,10 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
453 HEXDUMP16(WARN,"irb: ",irb); 463 HEXDUMP16(WARN,"irb: ",irb);
454 HEXDUMP16(WARN,"sense data: ",irb->ecw); 464 HEXDUMP16(WARN,"sense data: ",irb->ecw);
455 } 465 }
466 if (intparm == QETH_RCD_PARM) {
467 channel->state = CH_STATE_DOWN;
468 goto out;
469 }
456 rc = qeth_get_problem(cdev,irb); 470 rc = qeth_get_problem(cdev,irb);
457 if (rc) { 471 if (rc) {
458 qeth_schedule_recovery(card); 472 qeth_schedule_recovery(card);
@@ -460,6 +474,10 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
460 } 474 }
461 } 475 }
462 476
477 if (intparm == QETH_RCD_PARM) {
478 channel->state = CH_STATE_RCD_DONE;
479 goto out;
480 }
463 if (intparm) { 481 if (intparm) {
464 buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm); 482 buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
465 buffer->state = BUF_STATE_PROCESSED; 483 buffer->state = BUF_STATE_PROCESSED;
@@ -1204,6 +1222,54 @@ qeth_probe_device(struct ccwgroup_device *gdev)
1204} 1222}
1205 1223
1206 1224
1225static int qeth_read_conf_data(struct qeth_card *card, void **buffer,
1226 int *length)
1227{
1228 struct ciw *ciw;
1229 char *rcd_buf;
1230 int ret;
1231 struct qeth_channel *channel = &card->data;
1232 unsigned long flags;
1233
1234 /*
1235 * scan for RCD command in extended SenseID data
1236 */
1237 ciw = ccw_device_get_ciw(channel->ccwdev, CIW_TYPE_RCD);
1238 if (!ciw || ciw->cmd == 0)
1239 return -EOPNOTSUPP;
1240 rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
1241 if (!rcd_buf)
1242 return -ENOMEM;
1243
1244 channel->ccw.cmd_code = ciw->cmd;
1245 channel->ccw.cda = (__u32) __pa (rcd_buf);
1246 channel->ccw.count = ciw->count;
1247 channel->ccw.flags = CCW_FLAG_SLI;
1248 channel->state = CH_STATE_RCD;
1249 spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
1250 ret = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
1251 QETH_RCD_PARM, LPM_ANYPATH, 0,
1252 QETH_RCD_TIMEOUT);
1253 spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
1254 if (!ret)
1255 wait_event(card->wait_q,
1256 (channel->state == CH_STATE_RCD_DONE ||
1257 channel->state == CH_STATE_DOWN));
1258 if (channel->state == CH_STATE_DOWN)
1259 ret = -EIO;
1260 else
1261 channel->state = CH_STATE_DOWN;
1262 if (ret) {
1263 kfree(rcd_buf);
1264 *buffer = NULL;
1265 *length = 0;
1266 } else {
1267 *length = ciw->count;
1268 *buffer = rcd_buf;
1269 }
1270 return ret;
1271}
1272
1207static int 1273static int
1208qeth_get_unitaddr(struct qeth_card *card) 1274qeth_get_unitaddr(struct qeth_card *card)
1209{ 1275{
@@ -1212,9 +1278,9 @@ qeth_get_unitaddr(struct qeth_card *card)
1212 int rc; 1278 int rc;
1213 1279
1214 QETH_DBF_TEXT(setup, 2, "getunit"); 1280 QETH_DBF_TEXT(setup, 2, "getunit");
1215 rc = read_conf_data(CARD_DDEV(card), (void **) &prcd, &length); 1281 rc = qeth_read_conf_data(card, (void **) &prcd, &length);
1216 if (rc) { 1282 if (rc) {
1217 PRINT_ERR("read_conf_data for device %s returned %i\n", 1283 PRINT_ERR("qeth_read_conf_data for device %s returned %i\n",
1218 CARD_DDEV_ID(card), rc); 1284 CARD_DDEV_ID(card), rc);
1219 return rc; 1285 return rc;
1220 } 1286 }
@@ -1223,6 +1289,7 @@ qeth_get_unitaddr(struct qeth_card *card)
1223 card->info.cula = prcd[63]; 1289 card->info.cula = prcd[63];
1224 card->info.guestlan = ((prcd[0x10] == _ascebc['V']) && 1290 card->info.guestlan = ((prcd[0x10] == _ascebc['V']) &&
1225 (prcd[0x11] == _ascebc['M'])); 1291 (prcd[0x11] == _ascebc['M']));
1292 kfree(prcd);
1226 return 0; 1293 return 0;
1227} 1294}
1228 1295