diff options
Diffstat (limited to 'drivers/message/i2o/i2o_scsi.c')
-rw-r--r-- | drivers/message/i2o/i2o_scsi.c | 202 |
1 files changed, 65 insertions, 137 deletions
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index fef53b509a61..9f1744c3933b 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c | |||
@@ -40,7 +40,6 @@ | |||
40 | * Fix the resource management problems. | 40 | * Fix the resource management problems. |
41 | */ | 41 | */ |
42 | 42 | ||
43 | #define DEBUG 1 | ||
44 | #include <linux/module.h> | 43 | #include <linux/module.h> |
45 | #include <linux/kernel.h> | 44 | #include <linux/kernel.h> |
46 | #include <linux/types.h> | 45 | #include <linux/types.h> |
@@ -338,162 +337,89 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m, | |||
338 | struct i2o_message *msg) | 337 | struct i2o_message *msg) |
339 | { | 338 | { |
340 | struct scsi_cmnd *cmd; | 339 | struct scsi_cmnd *cmd; |
340 | u32 error; | ||
341 | struct device *dev; | 341 | struct device *dev; |
342 | u8 as, ds, st; | ||
343 | 342 | ||
344 | cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt)); | 343 | cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt)); |
345 | 344 | if (unlikely(!cmd)) { | |
346 | if (msg->u.head[0] & (1 << 13)) { | 345 | osm_err("NULL reply received!\n"); |
347 | struct i2o_message __iomem *pmsg; /* preserved message */ | 346 | return -1; |
348 | u32 pm; | ||
349 | int err = DID_ERROR; | ||
350 | |||
351 | pm = le32_to_cpu(msg->body[3]); | ||
352 | |||
353 | pmsg = i2o_msg_in_to_virt(c, pm); | ||
354 | |||
355 | osm_err("IOP fail.\n"); | ||
356 | osm_err("From %d To %d Cmd %d.\n", | ||
357 | (msg->u.head[1] >> 12) & 0xFFF, | ||
358 | msg->u.head[1] & 0xFFF, msg->u.head[1] >> 24); | ||
359 | osm_err("Failure Code %d.\n", msg->body[0] >> 24); | ||
360 | if (msg->body[0] & (1 << 16)) | ||
361 | osm_err("Format error.\n"); | ||
362 | if (msg->body[0] & (1 << 17)) | ||
363 | osm_err("Path error.\n"); | ||
364 | if (msg->body[0] & (1 << 18)) | ||
365 | osm_err("Path State.\n"); | ||
366 | if (msg->body[0] & (1 << 18)) | ||
367 | { | ||
368 | osm_err("Congestion.\n"); | ||
369 | err = DID_BUS_BUSY; | ||
370 | } | ||
371 | |||
372 | osm_debug("Failing message is %p.\n", pmsg); | ||
373 | |||
374 | cmd = i2o_cntxt_list_get(c, readl(&pmsg->u.s.tcntxt)); | ||
375 | if (!cmd) | ||
376 | return 1; | ||
377 | |||
378 | cmd->result = err << 16; | ||
379 | cmd->scsi_done(cmd); | ||
380 | |||
381 | /* Now flush the message by making it a NOP */ | ||
382 | i2o_msg_nop(c, pm); | ||
383 | |||
384 | return 1; | ||
385 | } | 347 | } |
386 | 348 | ||
387 | /* | 349 | /* |
388 | * Low byte is device status, next is adapter status, | 350 | * Low byte is device status, next is adapter status, |
389 | * (then one byte reserved), then request status. | 351 | * (then one byte reserved), then request status. |
390 | */ | 352 | */ |
391 | ds = (u8) le32_to_cpu(msg->body[0]); | 353 | error = le32_to_cpu(msg->body[0]); |
392 | as = (u8) (le32_to_cpu(msg->body[0]) >> 8); | ||
393 | st = (u8) (le32_to_cpu(msg->body[0]) >> 24); | ||
394 | 354 | ||
355 | osm_debug("Completed %ld\n", cmd->serial_number); | ||
356 | |||
357 | cmd->result = error & 0xff; | ||
395 | /* | 358 | /* |
396 | * Is this a control request coming back - eg an abort ? | 359 | * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let |
360 | * the SCSI layer handle the error | ||
397 | */ | 361 | */ |
362 | if (cmd->result) | ||
363 | memcpy(cmd->sense_buffer, &msg->body[3], | ||
364 | min(sizeof(cmd->sense_buffer), (size_t) 40)); | ||
398 | 365 | ||
399 | if (!cmd) { | 366 | /* only output error code if AdapterStatus is not HBA_SUCCESS */ |
400 | if (st) | 367 | if ((error >> 8) & 0xff) |
401 | osm_warn("SCSI abort: %08X", le32_to_cpu(msg->body[0])); | 368 | osm_err("SCSI error %08x\n", error); |
402 | osm_info("SCSI abort completed.\n"); | ||
403 | return -EFAULT; | ||
404 | } | ||
405 | 369 | ||
406 | osm_debug("Completed %ld\n", cmd->serial_number); | 370 | dev = &c->pdev->dev; |
371 | if (cmd->use_sg) | ||
372 | dma_unmap_sg(dev, cmd->request_buffer, cmd->use_sg, | ||
373 | cmd->sc_data_direction); | ||
374 | else if (cmd->SCp.dma_handle) | ||
375 | dma_unmap_single(dev, cmd->SCp.dma_handle, cmd->request_bufflen, | ||
376 | cmd->sc_data_direction); | ||
407 | 377 | ||
408 | if (st) { | 378 | cmd->scsi_done(cmd); |
409 | u32 count, error; | ||
410 | /* An error has occurred */ | ||
411 | |||
412 | switch (st) { | ||
413 | case 0x06: | ||
414 | count = le32_to_cpu(msg->body[1]); | ||
415 | if (count < cmd->underflow) { | ||
416 | int i; | ||
417 | |||
418 | osm_err("SCSI underflow 0x%08X 0x%08X\n", count, | ||
419 | cmd->underflow); | ||
420 | osm_debug("Cmd: "); | ||
421 | for (i = 0; i < 15; i++) | ||
422 | pr_debug("%02X ", cmd->cmnd[i]); | ||
423 | pr_debug(".\n"); | ||
424 | cmd->result = (DID_ERROR << 16); | ||
425 | } | ||
426 | break; | ||
427 | 379 | ||
428 | default: | 380 | return 1; |
429 | error = le32_to_cpu(msg->body[0]); | 381 | }; |
430 | |||
431 | osm_err("SCSI error %08x\n", error); | ||
432 | |||
433 | if ((error & 0xff) == 0x02 /*CHECK_CONDITION */ ) { | ||
434 | int i; | ||
435 | u32 len = sizeof(cmd->sense_buffer); | ||
436 | len = (len > 40) ? 40 : len; | ||
437 | // Copy over the sense data | ||
438 | memcpy(cmd->sense_buffer, (void *)&msg->body[3], | ||
439 | len); | ||
440 | for (i = 0; i <= len; i++) | ||
441 | osm_info("%02x\n", | ||
442 | cmd->sense_buffer[i]); | ||
443 | if (cmd->sense_buffer[0] == 0x70 | ||
444 | && cmd->sense_buffer[2] == DATA_PROTECT) { | ||
445 | /* This is to handle an array failed */ | ||
446 | cmd->result = (DID_TIME_OUT << 16); | ||
447 | printk(KERN_WARNING "%s: SCSI Data " | ||
448 | "Protect-Device (%d,%d,%d) " | ||
449 | "hba_status=0x%x, dev_status=" | ||
450 | "0x%x, cmd=0x%x\n", c->name, | ||
451 | (u32) cmd->device->channel, | ||
452 | (u32) cmd->device->id, | ||
453 | (u32) cmd->device->lun, | ||
454 | (error >> 8) & 0xff, | ||
455 | error & 0xff, cmd->cmnd[0]); | ||
456 | } else | ||
457 | cmd->result = (DID_ERROR << 16); | ||
458 | |||
459 | break; | ||
460 | } | ||
461 | |||
462 | switch (as) { | ||
463 | case 0x0E: | ||
464 | /* SCSI Reset */ | ||
465 | cmd->result = DID_RESET << 16; | ||
466 | break; | ||
467 | |||
468 | case 0x0F: | ||
469 | cmd->result = DID_PARITY << 16; | ||
470 | break; | ||
471 | |||
472 | default: | ||
473 | cmd->result = DID_ERROR << 16; | ||
474 | break; | ||
475 | } | ||
476 | 382 | ||
477 | break; | 383 | /** |
478 | } | 384 | * i2o_scsi_notify_device_add - Retrieve notifications of added devices |
385 | * @i2o_dev: the I2O device which was added | ||
386 | * | ||
387 | * If a I2O device is added we catch the notification, because I2O classes | ||
388 | * other then SCSI peripheral will not be received through | ||
389 | * i2o_scsi_probe(). | ||
390 | */ | ||
391 | static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev) | ||
392 | { | ||
393 | switch (i2o_dev->lct_data.class_id) { | ||
394 | case I2O_CLASS_EXECUTIVE: | ||
395 | case I2O_CLASS_RANDOM_BLOCK_STORAGE: | ||
396 | i2o_scsi_probe(&i2o_dev->device); | ||
397 | break; | ||
479 | 398 | ||
480 | cmd->scsi_done(cmd); | 399 | default: |
481 | return 1; | 400 | break; |
482 | } | 401 | } |
402 | }; | ||
483 | 403 | ||
484 | cmd->result = DID_OK << 16 | ds; | 404 | /** |
485 | 405 | * i2o_scsi_notify_device_remove - Retrieve notifications of removed | |
486 | dev = &c->pdev->dev; | 406 | * devices |
487 | if (cmd->use_sg) | 407 | * @i2o_dev: the I2O device which was removed |
488 | dma_unmap_sg(dev, (struct scatterlist *)cmd->buffer, | 408 | * |
489 | cmd->use_sg, cmd->sc_data_direction); | 409 | * If a I2O device is removed, we catch the notification to remove the |
490 | else if (cmd->request_bufflen) | 410 | * corresponding SCSI device. |
491 | dma_unmap_single(dev, (dma_addr_t) ((long)cmd->SCp.ptr), | 411 | */ |
492 | cmd->request_bufflen, cmd->sc_data_direction); | 412 | static void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev) |
493 | 413 | { | |
494 | cmd->scsi_done(cmd); | 414 | switch (i2o_dev->lct_data.class_id) { |
415 | case I2O_CLASS_EXECUTIVE: | ||
416 | case I2O_CLASS_RANDOM_BLOCK_STORAGE: | ||
417 | i2o_scsi_remove(&i2o_dev->device); | ||
418 | break; | ||
495 | 419 | ||
496 | return 1; | 420 | default: |
421 | break; | ||
422 | } | ||
497 | }; | 423 | }; |
498 | 424 | ||
499 | /** | 425 | /** |
@@ -554,6 +480,8 @@ static struct i2o_driver i2o_scsi_driver = { | |||
554 | .name = OSM_NAME, | 480 | .name = OSM_NAME, |
555 | .reply = i2o_scsi_reply, | 481 | .reply = i2o_scsi_reply, |
556 | .classes = i2o_scsi_class_id, | 482 | .classes = i2o_scsi_class_id, |
483 | .notify_device_add = i2o_scsi_notify_device_add, | ||
484 | .notify_device_remove = i2o_scsi_notify_device_remove, | ||
557 | .notify_controller_add = i2o_scsi_notify_controller_add, | 485 | .notify_controller_add = i2o_scsi_notify_controller_add, |
558 | .notify_controller_remove = i2o_scsi_notify_controller_remove, | 486 | .notify_controller_remove = i2o_scsi_notify_controller_remove, |
559 | .driver = { | 487 | .driver = { |
@@ -712,7 +640,7 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt, | |||
712 | */ | 640 | */ |
713 | 641 | ||
714 | /* Attach tags to the devices */ | 642 | /* Attach tags to the devices */ |
715 | /* | 643 | /* FIXME: implement |
716 | if(SCpnt->device->tagged_supported) { | 644 | if(SCpnt->device->tagged_supported) { |
717 | if(SCpnt->tag == HEAD_OF_QUEUE_TAG) | 645 | if(SCpnt->tag == HEAD_OF_QUEUE_TAG) |
718 | scsi_flags |= 0x01000000; | 646 | scsi_flags |= 0x01000000; |