diff options
Diffstat (limited to 'drivers/s390/net/qeth_main.c')
-rw-r--r-- | drivers/s390/net/qeth_main.c | 77 |
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 | ||
317 | static long | 317 | static 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 | ||
1225 | static 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 | |||
1207 | static int | 1273 | static int |
1208 | qeth_get_unitaddr(struct qeth_card *card) | 1274 | qeth_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 | ||