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
each attached FiberChannel device to sysfs, say Y.
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
menu "SCSI low-level drivers"
......
......@@ -28,7 +28,7 @@ obj-$(CONFIG_SCSI) += scsi_mod.o
# --------------------------
obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.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_A3000_SCSI) += a3000.o wd33c93.o
......
This diff is collapsed.
......@@ -79,6 +79,8 @@ void scsi_remove_host(struct Scsi_Host *shost)
set_bit(SHOST_DEL, &shost->shost_state);
if (shost->transportt->host_destroy)
shost->transportt->host_destroy(shost);
class_device_unregister(&shost->shost_classdev);
if (shost->transport_classdev.class)
class_device_unregister(&shost->transport_classdev);
......@@ -133,11 +135,14 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
error = scsi_sysfs_add_host(shost);
if (error)
goto out_del_classdev;
goto out_destroy_host;
scsi_proc_host_add(shost);
return error;
out_destroy_host:
if (shost->transportt->host_destroy)
shost->transportt->host_destroy(shost);
out_del_classdev:
class_device_del(&shost->shost_classdev);
out_del_gendev:
......
This diff is collapsed.
......@@ -268,16 +268,42 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
*
* Return value:
* 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)
{
if (!SCSI_SENSE_VALID(scmd))
return FAILED;
struct scsi_sense_hdr sshdr;
if (! scsi_command_normalize_sense(scmd, &sshdr))
return FAILED; /* no valid sense data */
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 (scmd->sense_buffer[2] & 0xf) {
switch (sshdr.sense_key) {
case NO_SENSE:
return SUCCESS;
case RECOVERED_ERROR:
......@@ -301,19 +327,15 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
* if the device is in the process of becoming ready, we
* should retry.
*/
if ((scmd->sense_buffer[12] == 0x04) &&
(scmd->sense_buffer[13] == 0x01)) {
if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01))
return NEEDS_RETRY;
}
/*
* if the device is not started, we need to wake
* the error handler to start the motor
*/
if (scmd->device->allow_restart &&
(scmd->sense_buffer[12] == 0x04) &&
(scmd->sense_buffer[13] == 0x02)) {
(sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
return FAILED;
}
return SUCCESS;
/* these three are not supported */
......@@ -1358,7 +1380,8 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
return SUCCESS;
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->id, scmd->device->lun);
return SUCCESS; /* causes immediate i/o error */
......
......@@ -21,6 +21,7 @@
#include <scsi/scsi_ioctl.h>
#include <scsi/scsi_request.h>
#include <scsi/sg.h>
#include <scsi/scsi_dbg.h>
#include "scsi_logging.h"
......@@ -94,12 +95,13 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
{
struct scsi_request *sreq;
int result;
struct scsi_sense_hdr sshdr;
SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd));
sreq = scsi_allocate_request(sdev, GFP_KERNEL);
if (!sreq) {
printk("SCSI internal ioctl failed, no memory\n");
printk(KERN_WARNING "SCSI internal ioctl failed, no memory\n");
return -ENOMEM;
}
......@@ -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));
if (driver_byte(sreq->sr_result)) {
switch (sreq->sr_sense_buffer[2] & 0xf) {
if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) &&
(scsi_request_normalize_sense(sreq, &sshdr))) {
switch (sshdr.sense_key) {
case ILLEGAL_REQUEST:
if (cmd[0] == ALLOW_MEDIUM_REMOVAL)
sdev->lockable = 0;
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;
case NOT_READY: /* This happens if there is no disc in drive */
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;
}
case UNIT_ATTENTION:
......@@ -128,16 +134,15 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
break;
}
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->channel,
sdev->id,
sdev->lun,
sreq->sr_result);
printk("\tSense class %x, sense error %x, extended sense %x\n",
sense_class(sreq->sr_sense_buffer[0]),
sense_error(sreq->sr_sense_buffer[0]),
sreq->sr_sense_buffer[2] & 0xf);
scsi_print_req_sense(" ", sreq);
break;
}
}
......@@ -401,7 +406,8 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
case SCSI_IOCTL_SYNC:
case SCSI_IOCTL_START_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;
default:
break;
......
......@@ -718,7 +718,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
clear_errors = 0;
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];
......@@ -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);
return;
case VOLUME_OVERFLOW:
printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ",
cmd->device->host->host_no, (int) cmd->device->channel,
(int) cmd->device->id, (int) cmd->device->lun);
printk(KERN_INFO "Volume overflow <%d %d %d %d> CDB: ",
cmd->device->host->host_no,
(int)cmd->device->channel,
(int)cmd->device->id, (int)cmd->device->lun);
__scsi_print_command(cmd->data_cmnd);
scsi_print_sense("", cmd);
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,
return;
}
if (result) {
printk("SCSI error : <%d %d %d %d> return code = 0x%x\n",
cmd->device->host->host_no,
printk(KERN_INFO "SCSI error : <%d %d %d %d> return code "
"= 0x%x\n", cmd->device->host->host_no,
cmd->device->channel,
cmd->device->id,
cmd->device->lun, result);
......@@ -1604,13 +1605,16 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
sreq->sr_data_direction = DMA_NONE;
scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries);
if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) &&
((sreq->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION ||
(sreq->sr_sense_buffer[2] & 0x0f) == NOT_READY) &&
sdev->removable) {
if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && sdev->removable) {
struct scsi_sense_hdr sshdr;
if ((scsi_request_normalize_sense(sreq, &sshdr)) &&
((sshdr.sense_key == UNIT_ATTENTION) ||
(sshdr.sense_key == NOT_READY))) {
sdev->changed = 1;
sreq->sr_result = 0;
}
}
result = sreq->sr_result;
scsi_release_request(sreq);
return result;
......@@ -1668,6 +1672,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
case SDEV_CREATED:
case SDEV_RUNNING:
case SDEV_QUIESCE:
case SDEV_BLOCK:
break;
default:
goto illegal;
......
......@@ -39,6 +39,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_request.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_eh.h>
#include "scsi_priv.h"
#include "scsi_logging.h"
......@@ -253,6 +254,11 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
sdev->request_queue->queuedata = sdev;
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) {
ret = shost->hostt->slave_alloc(sdev);
if (ret) {
......@@ -262,15 +268,10 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
*/
if (ret == -ENXIO)
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)
goto out_cleanup_slave;
......@@ -290,6 +291,9 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
out_cleanup_slave:
if (shost->hostt->slave_destroy)
shost->hostt->slave_destroy(sdev);
out_device_destroy:
if (shost->transportt->device_destroy)
shost->transportt->device_destroy(sdev);
out_free_queue:
scsi_free_queue(sdev->request_queue);
out_free_dev:
......@@ -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 response_len = 0;
int pass, count;
struct scsi_sense_hdr sshdr;
*bflags = 0;
......@@ -357,18 +362,21 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
sreq->sr_result));
if (sreq->sr_result) {
/* not-ready to ready transition or power-on - good */
/* dpg: bogus? INQUIRY never returns UNIT_ATTENTION */
/* Supposedly, but many buggy devices do so anyway. */
/*
* not-ready to ready transition [asc/ascq=0x28/0x0]
* or power-on, reset [asc/ascq=0x29/0x0], continue.
* INQUIRY should not yield UNIT_ATTENTION
* but many buggy devices do so anyway.
*/
if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) &&
(sreq->sr_sense_buffer[2] & 0xf) ==
UNIT_ATTENTION &&
(sreq->sr_sense_buffer[12] == 0x28 ||
sreq->sr_sense_buffer[12] == 0x29) &&
sreq->sr_sense_buffer[13] == 0)
scsi_request_normalize_sense(sreq, &sshdr)) {
if ((sshdr.sense_key == UNIT_ATTENTION) &&
((sshdr.asc == 0x28) ||
(sshdr.asc == 0x29)) &&
(sshdr.ascq == 0))
continue;
}
}
break;
}
......@@ -741,6 +749,8 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
} else {
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->device_destroy)
sdev->host->transportt->device_destroy(sdev);
put_device(&sdev->sdev_gendev);
}
out:
......@@ -893,6 +903,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
struct scsi_lun *lunp, *lun_data;
struct scsi_request *sreq;
u8 *data;
struct scsi_sense_hdr sshdr;
/*
* 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,
" %s (try %d) result 0x%x\n", sreq->sr_result
? "failed" : "successful", retries,
sreq->sr_result));
if (sreq->sr_result == 0 ||
sreq->sr_sense_buffer[2] != UNIT_ATTENTION)
if (sreq->sr_result == 0)
break;
else if (scsi_request_normalize_sense(sreq, &sshdr)) {
if (sshdr.sense_key != UNIT_ATTENTION)
break;
}
}
if (sreq->sr_result) {
......@@ -1299,5 +1313,7 @@ void scsi_free_host_dev(struct scsi_device *sdev)
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->device_destroy)
sdev->host->transportt->device_destroy(sdev);
put_device(&sdev->sdev_gendev);
}
......@@ -169,7 +169,10 @@ void scsi_device_dev_release(struct device *dev)
if (delete) {
struct scsi_target *starget = to_scsi_target(parent);
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
if (!starget->create) {
if (shost->transportt->target_destroy)
shost->transportt->target_destroy(starget);
device_del(parent);
if (starget->transport_classdev.class)
class_device_unregister(&starget->transport_classdev);
......@@ -601,6 +604,8 @@ void scsi_remove_device(struct scsi_device *sdev)
scsi_device_set_state(sdev, SDEV_DEL);
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->device_destroy)
sdev->host->transportt->device_destroy(sdev);
put_device(&sdev->sdev_gendev);
out:
......
......@@ -29,6 +29,8 @@
static void transport_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_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)
fc_starget_port_name(starget) = -1;
fc_starget_port_id(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;
}
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)
{
/*
......@@ -99,10 +109,18 @@ static int fc_setup_host_transport_attrs(struct Scsi_Host *shost)
* all transport attributes to valid values per host.
*/
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;
}
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)
{
struct scsi_target *starget = transport_class_to_starget(class_dev);
......@@ -277,11 +295,13 @@ fc_attach_transport(struct fc_function_template *ft)
i->t.target_attrs = &i->starget_attrs[0];
i->t.target_class = &fc_transport_class;
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.host_attrs = &i->host_attrs[0];
i->t.host_class = &fc_host_class;
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->f = ft;
......@@ -353,7 +373,7 @@ static int fc_device_unblock(struct device *dev, void *data)
* that fail to recover 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;
......@@ -388,7 +408,7 @@ int
fc_target_block(struct scsi_target *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)
return -EINVAL;
......@@ -396,10 +416,7 @@ fc_target_block(struct scsi_target *starget)
device_for_each_child(&starget->dev, NULL, fc_device_block);
/* The scsi lld blocks this target for the timeout period only. */
timer->data = (unsigned long)starget;
timer->expires = jiffies + timeout * HZ;
timer->function = fc_timeout_blocked_tgt;
add_timer(timer);
schedule_delayed_work(work, timeout * HZ);
return 0;
}
......@@ -424,7 +441,8 @@ fc_target_unblock(struct scsi_target *starget)
* failure as the state machine state change will validate the
* 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);
}
......@@ -436,7 +454,7 @@ EXPORT_SYMBOL(fc_target_unblock);
* @data: scsi host that failed to recover its devices in the alloted
* 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_device *sdev;
......@@ -475,7 +493,7 @@ fc_host_block(struct Scsi_Host *shost)
{
struct scsi_device *sdev;
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)
return -EINVAL;
......@@ -484,11 +502,7 @@ fc_host_block(struct Scsi_Host *shost)
scsi_internal_device_block(sdev);
}
/* The scsi lld blocks this host for the timeout period only. */
timer->data = (unsigned long)shost;
timer->expires = jiffies + timeout * HZ;
timer->function = fc_timeout_blocked_host;
add_timer(timer);
schedule_delayed_work(work, timeout * HZ);
return 0;
}
......@@ -516,7 +530,9 @@ fc_host_unblock(struct Scsi_Host *shost)
* failure as the state machine state change will validate the
* 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) {
scsi_internal_device_unblock(sdev);
}
......
This diff is collapsed.
......@@ -40,6 +40,11 @@ struct scsi_transport_template {
int (*target_setup)(struct scsi_target *);
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
* space of this size will be left at the end of the
* scsi_* structure */
......
......@@ -29,7 +29,7 @@ struct fc_starget_attrs { /* aka fc_target_attrs */
uint64_t node_name;
uint64_t port_name;
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) \
......@@ -40,18 +40,18 @@ struct fc_starget_attrs { /* aka fc_target_attrs */
(((struct fc_starget_attrs *)&(x)->starget_data)->port_name)
#define fc_starget_dev_loss_tmo(x) \
(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_tmo)
#define fc_starget_dev_loss_timer(x) \
(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_timer)
#define fc_starget_dev_loss_work(x) \
(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_work)
struct fc_host_attrs {
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) \
(((struct fc_host_attrs *)(x)->shost_data)->link_down_tmo)
#define fc_host_link_down_timer(x) \
(((struct fc_host_attrs *)(x)->shost_data)->link_down_timer)
#define fc_host_link_down_work(x) \
(((struct fc_host_attrs *)(x)->shost_data)->link_down_work)
/* 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