Commit ac4646f7 authored by James Bottomley's avatar James Bottomley

Merge ssh://linux-scsi@linux-scsi.bkbits.net/scsi-misc-2.6

into mulgrave.(none):/home/jejb/BK/scsi-misc-2.6
parents 0a57a616 c53ba412
...@@ -203,6 +203,14 @@ config SCSI_FC_ATTRS ...@@ -203,6 +203,14 @@ config SCSI_FC_ATTRS
each attached FiberChannel device to sysfs, say Y. each attached FiberChannel device to sysfs, say Y.
Otherwise, say N. Otherwise, say N.
config SCSI_ISCSI_ATTRS
tristate "iSCSI Transport Attributes"
depends on SCSI
help
If you wish to export transport-specific information about
each attached iSCSI device to sysfs, say Y.
Otherwise, say N.
endmenu endmenu
menu "SCSI low-level drivers" menu "SCSI low-level drivers"
......
...@@ -28,7 +28,7 @@ obj-$(CONFIG_SCSI) += scsi_mod.o ...@@ -28,7 +28,7 @@ obj-$(CONFIG_SCSI) += scsi_mod.o
# -------------------------- # --------------------------
obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o
obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
......
This diff is collapsed.
...@@ -79,6 +79,8 @@ void scsi_remove_host(struct Scsi_Host *shost) ...@@ -79,6 +79,8 @@ void scsi_remove_host(struct Scsi_Host *shost)
set_bit(SHOST_DEL, &shost->shost_state); set_bit(SHOST_DEL, &shost->shost_state);
if (shost->transportt->host_destroy)
shost->transportt->host_destroy(shost);
class_device_unregister(&shost->shost_classdev); class_device_unregister(&shost->shost_classdev);
if (shost->transport_classdev.class) if (shost->transport_classdev.class)
class_device_unregister(&shost->transport_classdev); class_device_unregister(&shost->transport_classdev);
...@@ -133,11 +135,14 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev) ...@@ -133,11 +135,14 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
error = scsi_sysfs_add_host(shost); error = scsi_sysfs_add_host(shost);
if (error) if (error)
goto out_del_classdev; goto out_destroy_host;
scsi_proc_host_add(shost); scsi_proc_host_add(shost);
return error; return error;
out_destroy_host:
if (shost->transportt->host_destroy)
shost->transportt->host_destroy(shost);
out_del_classdev: out_del_classdev:
class_device_del(&shost->shost_classdev); class_device_del(&shost->shost_classdev);
out_del_gendev: out_del_gendev:
......
This diff is collapsed.
...@@ -268,16 +268,42 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, ...@@ -268,16 +268,42 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
* *
* Return value: * Return value:
* SUCCESS or FAILED or NEEDS_RETRY * SUCCESS or FAILED or NEEDS_RETRY
*
* Notes:
* When a deferred error is detected the current command has
* not been executed and needs retrying.
**/ **/
static int scsi_check_sense(struct scsi_cmnd *scmd) static int scsi_check_sense(struct scsi_cmnd *scmd)
{ {
if (!SCSI_SENSE_VALID(scmd)) struct scsi_sense_hdr sshdr;
return FAILED;
if (scmd->sense_buffer[2] & 0xe0) if (! scsi_command_normalize_sense(scmd, &sshdr))
return SUCCESS; return FAILED; /* no valid sense data */
switch (scmd->sense_buffer[2] & 0xf) { if (scsi_sense_is_deferred(&sshdr))
return NEEDS_RETRY;
/*
* Previous logic looked for FILEMARK, EOM or ILI which are
* mainly associated with tapes and returned SUCCESS.
*/
if (sshdr.response_code == 0x70) {
/* fixed format */
if (scmd->sense_buffer[2] & 0xe0)
return SUCCESS;
} else {
/*
* descriptor format: look for "stream commands sense data
* descriptor" (see SSC-3). Assume single sense data
* descriptor. Ignore ILI from SBC-2 READ LONG and WRITE LONG.
*/
if ((sshdr.additional_length > 3) &&
(scmd->sense_buffer[8] == 0x4) &&
(scmd->sense_buffer[11] & 0xe0))
return SUCCESS;
}
switch (sshdr.sense_key) {
case NO_SENSE: case NO_SENSE:
return SUCCESS; return SUCCESS;
case RECOVERED_ERROR: case RECOVERED_ERROR:
...@@ -301,19 +327,15 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) ...@@ -301,19 +327,15 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
* if the device is in the process of becoming ready, we * if the device is in the process of becoming ready, we
* should retry. * should retry.
*/ */
if ((scmd->sense_buffer[12] == 0x04) && if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01))
(scmd->sense_buffer[13] == 0x01)) {
return NEEDS_RETRY; return NEEDS_RETRY;
}
/* /*
* if the device is not started, we need to wake * if the device is not started, we need to wake
* the error handler to start the motor * the error handler to start the motor
*/ */
if (scmd->device->allow_restart && if (scmd->device->allow_restart &&
(scmd->sense_buffer[12] == 0x04) && (sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
(scmd->sense_buffer[13] == 0x02)) {
return FAILED; return FAILED;
}
return SUCCESS; return SUCCESS;
/* these three are not supported */ /* these three are not supported */
...@@ -1358,7 +1380,8 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) ...@@ -1358,7 +1380,8 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
return SUCCESS; return SUCCESS;
case RESERVATION_CONFLICT: case RESERVATION_CONFLICT:
printk("scsi%d (%d,%d,%d) : reservation conflict\n", printk(KERN_INFO "scsi: reservation conflict: host"
" %d channel %d id %d lun %d\n",
scmd->device->host->host_no, scmd->device->channel, scmd->device->host->host_no, scmd->device->channel,
scmd->device->id, scmd->device->lun); scmd->device->id, scmd->device->lun);
return SUCCESS; /* causes immediate i/o error */ return SUCCESS; /* causes immediate i/o error */
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <scsi/scsi_ioctl.h> #include <scsi/scsi_ioctl.h>
#include <scsi/scsi_request.h> #include <scsi/scsi_request.h>
#include <scsi/sg.h> #include <scsi/sg.h>
#include <scsi/scsi_dbg.h>
#include "scsi_logging.h" #include "scsi_logging.h"
...@@ -94,12 +95,13 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, ...@@ -94,12 +95,13 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
{ {
struct scsi_request *sreq; struct scsi_request *sreq;
int result; int result;
struct scsi_sense_hdr sshdr;
SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd));
sreq = scsi_allocate_request(sdev, GFP_KERNEL); sreq = scsi_allocate_request(sdev, GFP_KERNEL);
if (!sreq) { if (!sreq) {
printk("SCSI internal ioctl failed, no memory\n"); printk(KERN_WARNING "SCSI internal ioctl failed, no memory\n");
return -ENOMEM; return -ENOMEM;
} }
...@@ -108,17 +110,21 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, ...@@ -108,17 +110,21 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", sreq->sr_result)); SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", sreq->sr_result));
if (driver_byte(sreq->sr_result)) { if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) &&
switch (sreq->sr_sense_buffer[2] & 0xf) { (scsi_request_normalize_sense(sreq, &sshdr))) {
switch (sshdr.sense_key) {
case ILLEGAL_REQUEST: case ILLEGAL_REQUEST:
if (cmd[0] == ALLOW_MEDIUM_REMOVAL) if (cmd[0] == ALLOW_MEDIUM_REMOVAL)
sdev->lockable = 0; sdev->lockable = 0;
else else
printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); printk(KERN_INFO "ioctl_internal_command: "
"ILLEGAL REQUEST asc=0x%x ascq=0x%x\n",
sshdr.asc, sshdr.ascq);
break; break;
case NOT_READY: /* This happens if there is no disc in drive */ case NOT_READY: /* This happens if there is no disc in drive */
if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) { if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) {
printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); printk(KERN_INFO "Device not ready. Make sure"
" there is a disc in the drive.\n");
break; break;
} }
case UNIT_ATTENTION: case UNIT_ATTENTION:
...@@ -128,16 +134,15 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, ...@@ -128,16 +134,15 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
break; break;
} }
default: /* Fall through for non-removable media */ default: /* Fall through for non-removable media */
printk("SCSI error: host %d id %d lun %d return code = %x\n", printk(KERN_INFO "ioctl_internal_command: <%d %d %d "
"%d> return code = %x\n",
sdev->host->host_no, sdev->host->host_no,
sdev->channel,
sdev->id, sdev->id,
sdev->lun, sdev->lun,
sreq->sr_result); sreq->sr_result);
printk("\tSense class %x, sense error %x, extended sense %x\n", scsi_print_req_sense(" ", sreq);
sense_class(sreq->sr_sense_buffer[0]), break;
sense_error(sreq->sr_sense_buffer[0]),
sreq->sr_sense_buffer[2] & 0xf);
} }
} }
...@@ -401,7 +406,8 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) ...@@ -401,7 +406,8 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
case SCSI_IOCTL_SYNC: case SCSI_IOCTL_SYNC:
case SCSI_IOCTL_START_UNIT: case SCSI_IOCTL_START_UNIT:
case SCSI_IOCTL_STOP_UNIT: case SCSI_IOCTL_STOP_UNIT:
printk(KERN_WARNING "program %s is using a deprecated SCSI ioctl, please convert it to SG_IO\n", current->comm); printk(KERN_WARNING "program %s is using a deprecated SCSI "
"ioctl, please convert it to SG_IO\n", current->comm);
break; break;
default: default:
break; break;
......
...@@ -718,7 +718,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, ...@@ -718,7 +718,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
clear_errors = 0; clear_errors = 0;
if (scsi_command_normalize_sense(cmd, &sshdr)) { if (scsi_command_normalize_sense(cmd, &sshdr)) {
/* /*
* SG_IO wants to know about deferred errors * SG_IO wants current and deferred errors
*/ */
int len = 8 + cmd->sense_buffer[7]; int len = 8 + cmd->sense_buffer[7];
...@@ -844,9 +844,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, ...@@ -844,9 +844,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
cmd = scsi_end_request(cmd, 0, this_count, 1); cmd = scsi_end_request(cmd, 0, this_count, 1);
return; return;
case VOLUME_OVERFLOW: case VOLUME_OVERFLOW:
printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ", printk(KERN_INFO "Volume overflow <%d %d %d %d> CDB: ",
cmd->device->host->host_no, (int) cmd->device->channel, cmd->device->host->host_no,
(int) cmd->device->id, (int) cmd->device->lun); (int)cmd->device->channel,
(int)cmd->device->id, (int)cmd->device->lun);
__scsi_print_command(cmd->data_cmnd); __scsi_print_command(cmd->data_cmnd);
scsi_print_sense("", cmd); scsi_print_sense("", cmd);
cmd = scsi_end_request(cmd, 0, block_bytes, 1); cmd = scsi_end_request(cmd, 0, block_bytes, 1);
...@@ -865,8 +866,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, ...@@ -865,8 +866,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
return; return;
} }
if (result) { if (result) {
printk("SCSI error : <%d %d %d %d> return code = 0x%x\n", printk(KERN_INFO "SCSI error : <%d %d %d %d> return code "
cmd->device->host->host_no, "= 0x%x\n", cmd->device->host->host_no,
cmd->device->channel, cmd->device->channel,
cmd->device->id, cmd->device->id,
cmd->device->lun, result); cmd->device->lun, result);
...@@ -1604,12 +1605,15 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) ...@@ -1604,12 +1605,15 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
sreq->sr_data_direction = DMA_NONE; sreq->sr_data_direction = DMA_NONE;
scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries);
if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && sdev->removable) {
((sreq->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION || struct scsi_sense_hdr sshdr;
(sreq->sr_sense_buffer[2] & 0x0f) == NOT_READY) &&
sdev->removable) { if ((scsi_request_normalize_sense(sreq, &sshdr)) &&
sdev->changed = 1; ((sshdr.sense_key == UNIT_ATTENTION) ||
sreq->sr_result = 0; (sshdr.sense_key == NOT_READY))) {
sdev->changed = 1;
sreq->sr_result = 0;
}
} }
result = sreq->sr_result; result = sreq->sr_result;
scsi_release_request(sreq); scsi_release_request(sreq);
...@@ -1668,6 +1672,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) ...@@ -1668,6 +1672,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
case SDEV_CREATED: case SDEV_CREATED:
case SDEV_RUNNING: case SDEV_RUNNING:
case SDEV_QUIESCE: case SDEV_QUIESCE:
case SDEV_BLOCK:
break; break;
default: default:
goto illegal; goto illegal;
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_request.h> #include <scsi/scsi_request.h>
#include <scsi/scsi_transport.h> #include <scsi/scsi_transport.h>
#include <scsi/scsi_eh.h>
#include "scsi_priv.h" #include "scsi_priv.h"
#include "scsi_logging.h" #include "scsi_logging.h"
...@@ -253,6 +254,11 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -253,6 +254,11 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
sdev->request_queue->queuedata = sdev; sdev->request_queue->queuedata = sdev;
scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
if (shost->transportt->device_setup) {
if (shost->transportt->device_setup(sdev))
goto out_free_queue;
}
if (shost->hostt->slave_alloc) { if (shost->hostt->slave_alloc) {
ret = shost->hostt->slave_alloc(sdev); ret = shost->hostt->slave_alloc(sdev);
if (ret) { if (ret) {
...@@ -262,15 +268,10 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -262,15 +268,10 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
*/ */
if (ret == -ENXIO) if (ret == -ENXIO)
display_failure_msg = 0; display_failure_msg = 0;
goto out_free_queue; goto out_device_destroy;
} }
} }
if (shost->transportt->device_setup) {
if (shost->transportt->device_setup(sdev))
goto out_cleanup_slave;
}
if (scsi_sysfs_device_initialize(sdev) != 0) if (scsi_sysfs_device_initialize(sdev) != 0)
goto out_cleanup_slave; goto out_cleanup_slave;
...@@ -290,6 +291,9 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -290,6 +291,9 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
out_cleanup_slave: out_cleanup_slave:
if (shost->hostt->slave_destroy) if (shost->hostt->slave_destroy)
shost->hostt->slave_destroy(sdev); shost->hostt->slave_destroy(sdev);
out_device_destroy:
if (shost->transportt->device_destroy)
shost->transportt->device_destroy(sdev);
out_free_queue: out_free_queue:
scsi_free_queue(sdev->request_queue); scsi_free_queue(sdev->request_queue);
out_free_dev: out_free_dev:
...@@ -322,6 +326,7 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, ...@@ -322,6 +326,7 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
int first_inquiry_len, try_inquiry_len, next_inquiry_len; int first_inquiry_len, try_inquiry_len, next_inquiry_len;
int response_len = 0; int response_len = 0;
int pass, count; int pass, count;
struct scsi_sense_hdr sshdr;
*bflags = 0; *bflags = 0;
...@@ -357,17 +362,20 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, ...@@ -357,17 +362,20 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
sreq->sr_result)); sreq->sr_result));
if (sreq->sr_result) { if (sreq->sr_result) {
/*
/* not-ready to ready transition or power-on - good */ * not-ready to ready transition [asc/ascq=0x28/0x0]
/* dpg: bogus? INQUIRY never returns UNIT_ATTENTION */ * or power-on, reset [asc/ascq=0x29/0x0], continue.
/* Supposedly, but many buggy devices do so anyway. */ * INQUIRY should not yield UNIT_ATTENTION
* but many buggy devices do so anyway.
*/
if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) &&
(sreq->sr_sense_buffer[2] & 0xf) == scsi_request_normalize_sense(sreq, &sshdr)) {
UNIT_ATTENTION && if ((sshdr.sense_key == UNIT_ATTENTION) &&
(sreq->sr_sense_buffer[12] == 0x28 || ((sshdr.asc == 0x28) ||
sreq->sr_sense_buffer[12] == 0x29) && (sshdr.asc == 0x29)) &&
sreq->sr_sense_buffer[13] == 0) (sshdr.ascq == 0))
continue; continue;
}
} }
break; break;
} }
...@@ -741,6 +749,8 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host, ...@@ -741,6 +749,8 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
} else { } else {
if (sdev->host->hostt->slave_destroy) if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev); sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->device_destroy)
sdev->host->transportt->device_destroy(sdev);
put_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev);
} }
out: out:
...@@ -893,6 +903,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, ...@@ -893,6 +903,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
struct scsi_lun *lunp, *lun_data; struct scsi_lun *lunp, *lun_data;
struct scsi_request *sreq; struct scsi_request *sreq;
u8 *data; u8 *data;
struct scsi_sense_hdr sshdr;
/* /*
* Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set. * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
...@@ -970,9 +981,12 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, ...@@ -970,9 +981,12 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
" %s (try %d) result 0x%x\n", sreq->sr_result " %s (try %d) result 0x%x\n", sreq->sr_result
? "failed" : "successful", retries, ? "failed" : "successful", retries,
sreq->sr_result)); sreq->sr_result));
if (sreq->sr_result == 0 || if (sreq->sr_result == 0)
sreq->sr_sense_buffer[2] != UNIT_ATTENTION)
break; break;
else if (scsi_request_normalize_sense(sreq, &sshdr)) {
if (sshdr.sense_key != UNIT_ATTENTION)
break;
}
} }
if (sreq->sr_result) { if (sreq->sr_result) {
...@@ -1299,5 +1313,7 @@ void scsi_free_host_dev(struct scsi_device *sdev) ...@@ -1299,5 +1313,7 @@ void scsi_free_host_dev(struct scsi_device *sdev)
if (sdev->host->hostt->slave_destroy) if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev); sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->device_destroy)
sdev->host->transportt->device_destroy(sdev);
put_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev);
} }
...@@ -169,7 +169,10 @@ void scsi_device_dev_release(struct device *dev) ...@@ -169,7 +169,10 @@ void scsi_device_dev_release(struct device *dev)
if (delete) { if (delete) {
struct scsi_target *starget = to_scsi_target(parent); struct scsi_target *starget = to_scsi_target(parent);
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
if (!starget->create) { if (!starget->create) {
if (shost->transportt->target_destroy)
shost->transportt->target_destroy(starget);
device_del(parent); device_del(parent);
if (starget->transport_classdev.class) if (starget->transport_classdev.class)
class_device_unregister(&starget->transport_classdev); class_device_unregister(&starget->transport_classdev);
...@@ -601,6 +604,8 @@ void scsi_remove_device(struct scsi_device *sdev) ...@@ -601,6 +604,8 @@ void scsi_remove_device(struct scsi_device *sdev)
scsi_device_set_state(sdev, SDEV_DEL); scsi_device_set_state(sdev, SDEV_DEL);
if (sdev->host->hostt->slave_destroy) if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev); sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->device_destroy)
sdev->host->transportt->device_destroy(sdev);
put_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev);
out: out:
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
static void transport_class_release(struct class_device *class_dev); static void transport_class_release(struct class_device *class_dev);
static void host_class_release(struct class_device *class_dev); static void host_class_release(struct class_device *class_dev);
static void fc_timeout_blocked_host(void *data);
static void fc_timeout_blocked_tgt(void *data);
#define FC_STARGET_NUM_ATTRS 4 /* increase this if you add attributes */ #define FC_STARGET_NUM_ATTRS 4 /* increase this if you add attributes */
#define FC_STARGET_OTHER_ATTRS 0 /* increase this if you add "always on" #define FC_STARGET_OTHER_ATTRS 0 /* increase this if you add "always on"
...@@ -87,10 +89,18 @@ static int fc_setup_starget_transport_attrs(struct scsi_target *starget) ...@@ -87,10 +89,18 @@ static int fc_setup_starget_transport_attrs(struct scsi_target *starget)
fc_starget_port_name(starget) = -1; fc_starget_port_name(starget) = -1;
fc_starget_port_id(starget) = -1; fc_starget_port_id(starget) = -1;
fc_starget_dev_loss_tmo(starget) = -1; fc_starget_dev_loss_tmo(starget) = -1;
init_timer(&fc_starget_dev_loss_timer(starget)); INIT_WORK(&fc_starget_dev_loss_work(starget),
fc_timeout_blocked_tgt, starget);
return 0; return 0;
} }
static void fc_destroy_starget(struct scsi_target *starget)
{
/* Stop the target timer */
if (cancel_delayed_work(&fc_starget_dev_loss_work(starget)))
flush_scheduled_work();
}
static int fc_setup_host_transport_attrs(struct Scsi_Host *shost) static int fc_setup_host_transport_attrs(struct Scsi_Host *shost)
{ {
/* /*
...@@ -99,10 +109,18 @@ static int fc_setup_host_transport_attrs(struct Scsi_Host *shost) ...@@ -99,10 +109,18 @@ static int fc_setup_host_transport_attrs(struct Scsi_Host *shost)
* all transport attributes to valid values per host. * all transport attributes to valid values per host.
*/ */
fc_host_link_down_tmo(shost) = -1; fc_host_link_down_tmo(shost) = -1;
init_timer(&fc_host_link_down_timer(shost)); INIT_WORK(&fc_host_link_down_work(shost),
fc_timeout_blocked_host, shost);
return 0; return 0;
} }
static void fc_destroy_host(struct Scsi_Host *shost)
{
/* Stop the host timer */
if (cancel_delayed_work(&fc_host_link_down_work(shost)))
flush_scheduled_work();
}
static void transport_class_release(struct class_device *class_dev) static void transport_class_release(struct class_device *class_dev)
{ {
struct scsi_target *starget = transport_class_to_starget(class_dev); struct scsi_target *starget = transport_class_to_starget(class_dev);
...@@ -277,11 +295,13 @@ fc_attach_transport(struct fc_function_template *ft) ...@@ -277,11 +295,13 @@ fc_attach_transport(struct fc_function_template *ft)
i->t.target_attrs = &i->starget_attrs[0]; i->t.target_attrs = &i->starget_attrs[0];
i->t.target_class = &fc_transport_class; i->t.target_class = &fc_transport_class;
i->t.target_setup = &fc_setup_starget_transport_attrs; i->t.target_setup = &fc_setup_starget_transport_attrs;
i->t.target_destroy = &fc_destroy_starget;
i->t.target_size = sizeof(struct fc_starget_attrs); i->t.target_size = sizeof(struct fc_starget_attrs);
i->t.host_attrs = &i->host_attrs[0]; i->t.host_attrs = &i->host_attrs[0];
i->t.host_class = &fc_host_class; i->t.host_class = &fc_host_class;
i->t.host_setup = &fc_setup_host_transport_attrs; i->t.host_setup = &fc_setup_host_transport_attrs;
i->t.host_destroy = &fc_destroy_host;
i->t.host_size = sizeof(struct fc_host_attrs); i->t.host_size = sizeof(struct fc_host_attrs);
i->f = ft; i->f = ft;
...@@ -353,7 +373,7 @@ static int fc_device_unblock(struct device *dev, void *data) ...@@ -353,7 +373,7 @@ static int fc_device_unblock(struct device *dev, void *data)
* that fail to recover in the alloted time. * that fail to recover in the alloted time.
* @data: scsi target that failed to reappear in the alloted time. * @data: scsi target that failed to reappear in the alloted time.
**/ **/
static void fc_timeout_blocked_tgt(unsigned long data) static void fc_timeout_blocked_tgt(void *data)
{ {
struct scsi_target *starget = (struct scsi_target *)data; struct scsi_target *starget = (struct scsi_target *)data;
...@@ -388,7 +408,7 @@ int ...@@ -388,7 +408,7 @@ int
fc_target_block(struct scsi_target *starget) fc_target_block(struct scsi_target *starget)
{ {
int timeout = fc_starget_dev_loss_tmo(starget); int timeout = fc_starget_dev_loss_tmo(starget);
struct timer_list *timer = &fc_starget_dev_loss_timer(starget); struct work_struct *work = &fc_starget_dev_loss_work(starget);
if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
return -EINVAL; return -EINVAL;
...@@ -396,10 +416,7 @@ fc_target_block(struct scsi_target *starget) ...@@ -396,10 +416,7 @@ fc_target_block(struct scsi_target *starget)
device_for_each_child(&starget->dev, NULL, fc_device_block); device_for_each_child(&starget->dev, NULL, fc_device_block);
/* The scsi lld blocks this target for the timeout period only. */ /* The scsi lld blocks this target for the timeout period only. */
timer->data = (unsigned long)starget; schedule_delayed_work(work, timeout * HZ);
timer->expires = jiffies + timeout * HZ;
timer->function = fc_timeout_blocked_tgt;
add_timer(timer);
return 0; return 0;
} }
...@@ -424,7 +441,8 @@ fc_target_unblock(struct scsi_target *starget) ...@@ -424,7 +441,8 @@ fc_target_unblock(struct scsi_target *starget)
* failure as the state machine state change will validate the * failure as the state machine state change will validate the
* transaction. * transaction.
*/ */
del_timer_sync(&fc_starget_dev_loss_timer(starget)); if (cancel_delayed_work(&fc_starget_dev_loss_work(starget)))
flush_scheduled_work();
device_for_each_child(&starget->dev, NULL, fc_device_unblock); device_for_each_child(&starget->dev, NULL, fc_device_unblock);
} }
...@@ -436,7 +454,7 @@ EXPORT_SYMBOL(fc_target_unblock); ...@@ -436,7 +454,7 @@ EXPORT_SYMBOL(fc_target_unblock);
* @data: scsi host that failed to recover its devices in the alloted * @data: scsi host that failed to recover its devices in the alloted
* time. * time.
**/ **/
static void fc_timeout_blocked_host(unsigned long data) static void fc_timeout_blocked_host(void *data)
{ {
struct Scsi_Host *shost = (struct Scsi_Host *)data; struct Scsi_Host *shost = (struct Scsi_Host *)data;
struct scsi_device *sdev; struct scsi_device *sdev;
...@@ -475,7 +493,7 @@ fc_host_block(struct Scsi_Host *shost) ...@@ -475,7 +493,7 @@ fc_host_block(struct Scsi_Host *shost)
{ {
struct scsi_device *sdev; struct scsi_device *sdev;
int timeout = fc_host_link_down_tmo(shost); int timeout = fc_host_link_down_tmo(shost);
struct timer_list *timer = &fc_host_link_down_timer(shost); struct work_struct *work = &fc_host_link_down_work(shost);
if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
return -EINVAL; return -EINVAL;
...@@ -484,11 +502,7 @@ fc_host_block(struct Scsi_Host *shost) ...@@ -484,11 +502,7 @@ fc_host_block(struct Scsi_Host *shost)
scsi_internal_device_block(sdev); scsi_internal_device_block(sdev);
} }
/* The scsi lld blocks this host for the timeout period only. */ schedule_delayed_work(work, timeout * HZ);
timer->data = (unsigned long)shost;
timer->expires = jiffies + timeout * HZ;
timer->function = fc_timeout_blocked_host;
add_timer(timer);
return 0; return 0;
} }
...@@ -516,7 +530,9 @@ fc_host_unblock(struct Scsi_Host *shost) ...@@ -516,7 +530,9 @@ fc_host_unblock(struct Scsi_Host *shost)
* failure as the state machine state change will validate the * failure as the state machine state change will validate the
* transaction. * transaction.
*/ */
del_timer_sync(&fc_host_link_down_timer(shost)); if (cancel_delayed_work(&fc_host_link_down_work(shost)))
flush_scheduled_work();
shost_for_each_device(sdev, shost) { shost_for_each_device(sdev, shost) {
scsi_internal_device_unblock(sdev); scsi_internal_device_unblock(sdev);
} }
......
This diff is collapsed.
...@@ -40,6 +40,11 @@ struct scsi_transport_template { ...@@ -40,6 +40,11 @@ struct scsi_transport_template {
int (*target_setup)(struct scsi_target *); int (*target_setup)(struct scsi_target *);
int (*host_setup)(struct Scsi_Host *); int (*host_setup)(struct Scsi_Host *);
/* Destructor functions */
void (*device_destroy)(struct scsi_device *);
void (*target_destroy)(struct scsi_target *);
void (*host_destroy)(struct Scsi_Host *);
/* The size of the specific transport attribute structure (a /* The size of the specific transport attribute structure (a
* space of this size will be left at the end of the * space of this size will be left at the end of the
* scsi_* structure */ * scsi_* structure */
......
...@@ -29,7 +29,7 @@ struct fc_starget_attrs { /* aka fc_target_attrs */ ...@@ -29,7 +29,7 @@ struct fc_starget_attrs { /* aka fc_target_attrs */
uint64_t node_name; uint64_t node_name;
uint64_t port_name; uint64_t port_name;
uint32_t dev_loss_tmo; /* Remote Port loss timeout in seconds. */ uint32_t dev_loss_tmo; /* Remote Port loss timeout in seconds. */
struct timer_list dev_loss_timer; struct work_struct dev_loss_work;
}; };
#define fc_starget_port_id(x) \ #define fc_starget_port_id(x) \
...@@ -40,18 +40,18 @@ struct fc_starget_attrs { /* aka fc_target_attrs */ ...@@ -40,18 +40,18 @@ struct fc_starget_attrs { /* aka fc_target_attrs */
(((struct fc_starget_attrs *)&(x)->starget_data)->port_name) (((struct fc_starget_attrs *)&(x)->starget_data)->port_name)
#define fc_starget_dev_loss_tmo(x) \ #define fc_starget_dev_loss_tmo(x) \
(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_tmo) (((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_tmo)
#define fc_starget_dev_loss_timer(x) \ #define fc_starget_dev_loss_work(x) \
(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_timer) (((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_work)
struct fc_host_attrs { struct fc_host_attrs {
uint32_t link_down_tmo; /* Link Down timeout in seconds. */ uint32_t link_down_tmo; /* Link Down timeout in seconds. */
struct timer_list link_down_timer; struct work_struct link_down_work;
}; };
#define fc_host_link_down_tmo(x) \ #define fc_host_link_down_tmo(x) \
(((struct fc_host_attrs *)(x)->shost_data)->link_down_tmo) (((struct fc_host_attrs *)(x)->shost_data)->link_down_tmo)
#define fc_host_link_down_timer(x) \ #define fc_host_link_down_work(x) \
(((struct fc_host_attrs *)(x)->shost_data)->link_down_timer) (((struct fc_host_attrs *)(x)->shost_data)->link_down_work)
/* The functions by which the transport class and the driver communicate */ /* The functions by which the transport class and the driver communicate */
......
/*
* iSCSI transport class definitions
*
* Copyright (C) IBM Corporation, 2004
* Copyright (C) Mike Christie, 2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef SCSI_TRANSPORT_ISCSI_H
#define SCSI_TRANSPORT_ISCSI_H
#include <linux/config.h>
#include <linux/in6.h>
#include <linux/in.h>
struct scsi_transport_template;
struct iscsi_class_session {
uint8_t isid[6];
uint16_t tsih;
int header_digest; /* 1 CRC32, 0 None */
int data_digest; /* 1 CRC32, 0 None */
uint16_t tpgt;
union {
struct in6_addr sin6_addr;
struct in_addr sin_addr;
} u;
sa_family_t addr_type; /* must be AF_INET or AF_INET6 */
uint16_t port; /* must be in network byte order */
int initial_r2t; /* 1 Yes, 0 No */
int immediate_data; /* 1 Yes, 0 No */
uint32_t max_recv_data_segment_len;
uint32_t max_burst_len;
uint32_t first_burst_len;
uint16_t def_time2wait;
uint16_t def_time2retain;
uint16_t max_outstanding_r2t;
int data_pdu_in_order; /* 1 Yes, 0 No */
int data_sequence_in_order; /* 1 Yes, 0 No */
int erl;
};
/*
* accessor macros
*/
#define iscsi_isid(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->isid)
#define iscsi_tsih(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->tsih)
#define iscsi_header_digest(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->header_digest)
#define iscsi_data_digest(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->data_digest)
#define iscsi_port(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->port)
#define iscsi_addr_type(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->addr_type)
#define iscsi_sin_addr(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->u.sin_addr)
#define iscsi_sin6_addr(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->u.sin6_addr)
#define iscsi_tpgt(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->tpgt)
#define iscsi_initial_r2t(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->initial_r2t)
#define iscsi_immediate_data(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->immediate_data)
#define iscsi_max_recv_data_segment_len(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->max_recv_data_segment_len)
#define iscsi_max_burst_len(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->max_burst_len)
#define iscsi_first_burst_len(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->first_burst_len)
#define iscsi_def_time2wait(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->def_time2wait)
#define iscsi_def_time2retain(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->def_time2retain)
#define iscsi_max_outstanding_r2t(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->max_outstanding_r2t)
#define iscsi_data_pdu_in_order(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->data_pdu_in_order)
#define iscsi_data_sequence_in_order(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->data_sequence_in_order)
#define iscsi_erl(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->erl)
/*
* The functions by which the transport class and the driver communicate
*/
struct iscsi_function_template {
/*
* target attrs
*/
void (*get_isid)(struct scsi_target *);
void (*get_tsih)(struct scsi_target *);
void (*get_header_digest)(struct scsi_target *);
void (*get_data_digest)(struct scsi_target *);
void (*get_port)(struct scsi_target *);
void (*get_tpgt)(struct scsi_target *);
/*
* In get_ip_address the lld must set the address and
* the address type
*/
void (*get_ip_address)(struct scsi_target *);
/*
* The lld should snprintf the name or alias to the buffer
*/
ssize_t (*get_target_name)(struct scsi_target *, char *, ssize_t);
ssize_t (*get_target_alias)(struct scsi_target *, char *, ssize_t);
void (*get_initial_r2t)(struct scsi_target *);
void (*get_immediate_data)(struct scsi_target *);
void (*get_max_recv_data_segment_len)(struct scsi_target *);
void (*get_max_burst_len)(struct scsi_target *);
void (*get_first_burst_len)(struct scsi_target *);
void (*get_def_time2wait)(struct scsi_target *);
void (*get_def_time2retain)(struct scsi_target *);
void (*get_max_outstanding_r2t)(struct scsi_target *);
void (*get_data_pdu_in_order)(struct scsi_target *);
void (*get_data_sequence_in_order)(struct scsi_target *);
void (*get_erl)(struct scsi_target *);
/*
* host atts
*/
/*
* The lld should snprintf the name or alias to the buffer
*/
ssize_t (*get_initiator_alias)(struct Scsi_Host *, char *, ssize_t);
ssize_t (*get_initiator_name)(struct Scsi_Host *, char *, ssize_t);
/*
* The driver sets these to tell the transport class it
* wants the attributes displayed in sysfs. If the show_ flag
* is not set, the attribute will be private to the transport
* class. We could probably just test if a get_ fn was set
* since we only use the values for sysfs but this is how
* fc does it too.
*/
unsigned long show_isid:1;
unsigned long show_tsih:1;
unsigned long show_header_digest:1;
unsigned long show_data_digest:1;
unsigned long show_port:1;
unsigned long show_tpgt:1;
unsigned long show_ip_address:1;
unsigned long show_target_name:1;
unsigned long show_target_alias:1;
unsigned long show_initial_r2t:1;
unsigned long show_immediate_data:1;
unsigned long show_max_recv_data_segment_len:1;
unsigned long show_max_burst_len:1;
unsigned long show_first_burst_len:1;
unsigned long show_def_time2wait:1;
unsigned long show_def_time2retain:1;
unsigned long show_max_outstanding_r2t:1;
unsigned long show_data_pdu_in_order:1;
unsigned long show_data_sequence_in_order:1;
unsigned long show_erl:1;
unsigned long show_initiator_name:1;
unsigned long show_initiator_alias:1;
};
struct scsi_transport_template *iscsi_attach_transport(struct iscsi_function_template *);
void iscsi_release_transport(struct scsi_transport_template *);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment