Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6: (679 commits)
  commit 7676f83aeb
  Author: James Bottomley <James.Bottomley@steeleye.com>
  Date:   Fri Apr 14 09:47:59 2006 -0500
  
      [SCSI] scsi_transport_sas: don't scan a non-existent end device
      
      Any end device that can't support any of the scanning protocols
      shouldn't be scanned, so set its id to -1 to prevent
      scsi_scan_target() being called for it.
      
      Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
  
  commit 3c0c25b97c
  Author: Moore, Eric <Eric.Moore@lsil.com>
  Date:   Thu Apr 13 16:08:17 2006 -0600
  
      [SCSI] mptfusion - fix panic in mptsas_slave_configure
      
      Driver panic when RAID logical volume was present when driver
      loaded, or when a RAID logical volume was created on the fly.
  ...
This commit is contained in:
Linus Torvalds 2006-04-14 17:09:08 -07:00
commit f05472f10d
43 changed files with 1095 additions and 13266 deletions

View File

@ -350,16 +350,51 @@ out:
return ret; return ret;
} }
/**
* sg_scsi_ioctl -- handle deprecated SCSI_IOCTL_SEND_COMMAND ioctl
* @file: file this ioctl operates on (optional)
* @q: request queue to send scsi commands down
* @disk: gendisk to operate on (option)
* @sic: userspace structure describing the command to perform
*
* Send down the scsi command described by @sic to the device below
* the request queue @q. If @file is non-NULL it's used to perform
* fine-grained permission checks that allow users to send down
* non-destructive SCSI commands. If the caller has a struct gendisk
* available it should be passed in as @disk to allow the low level
* driver to use the information contained in it. A non-NULL @disk
* is only allowed if the caller knows that the low level driver doesn't
* need it (e.g. in the scsi subsystem).
*
* Notes:
* - This interface is deprecated - users should use the SG_IO
* interface instead, as this is a more flexible approach to
* performing SCSI commands on a device.
* - The SCSI command length is determined by examining the 1st byte
* of the given command. There is no way to override this.
* - Data transfers are limited to PAGE_SIZE
* - The length (x + y) must be at least OMAX_SB_LEN bytes long to
* accommodate the sense buffer when an error occurs.
* The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that
* old code will not be surprised.
* - If a Unix error occurs (e.g. ENOMEM) then the user will receive
* a negative return and the Unix error code in 'errno'.
* If the SCSI command succeeds then 0 is returned.
* Positive numbers returned are the compacted SCSI error codes (4
* bytes in one int) where the lowest byte is the SCSI status.
*/
#define OMAX_SB_LEN 16 /* For backward compatibility */ #define OMAX_SB_LEN 16 /* For backward compatibility */
int sg_scsi_ioctl(struct file *file, struct request_queue *q,
static int sg_scsi_ioctl(struct file *file, request_queue_t *q, struct gendisk *disk, struct scsi_ioctl_command __user *sic)
struct gendisk *bd_disk, Scsi_Ioctl_Command __user *sic)
{ {
struct request *rq; struct request *rq;
int err; int err;
unsigned int in_len, out_len, bytes, opcode, cmdlen; unsigned int in_len, out_len, bytes, opcode, cmdlen;
char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE]; char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE];
if (!sic)
return -EINVAL;
/* /*
* get in an out lengths, verify they don't exceed a page worth of data * get in an out lengths, verify they don't exceed a page worth of data
*/ */
@ -393,17 +428,21 @@ static int sg_scsi_ioctl(struct file *file, request_queue_t *q,
if (copy_from_user(rq->cmd, sic->data, cmdlen)) if (copy_from_user(rq->cmd, sic->data, cmdlen))
goto error; goto error;
if (copy_from_user(buffer, sic->data + cmdlen, in_len)) if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
goto error; goto error;
err = verify_command(file, rq->cmd); err = verify_command(file, rq->cmd);
if (err) if (err)
goto error; goto error;
/* default. possible overriden later */
rq->retries = 5;
switch (opcode) { switch (opcode) {
case SEND_DIAGNOSTIC: case SEND_DIAGNOSTIC:
case FORMAT_UNIT: case FORMAT_UNIT:
rq->timeout = FORMAT_UNIT_TIMEOUT; rq->timeout = FORMAT_UNIT_TIMEOUT;
rq->retries = 1;
break; break;
case START_STOP: case START_STOP:
rq->timeout = START_STOP_TIMEOUT; rq->timeout = START_STOP_TIMEOUT;
@ -416,22 +455,26 @@ static int sg_scsi_ioctl(struct file *file, request_queue_t *q,
break; break;
case READ_DEFECT_DATA: case READ_DEFECT_DATA:
rq->timeout = READ_DEFECT_DATA_TIMEOUT; rq->timeout = READ_DEFECT_DATA_TIMEOUT;
rq->retries = 1;
break; break;
default: default:
rq->timeout = BLK_DEFAULT_TIMEOUT; rq->timeout = BLK_DEFAULT_TIMEOUT;
break; break;
} }
if (bytes && blk_rq_map_kern(q, rq, buffer, bytes, __GFP_WAIT)) {
err = DRIVER_ERROR << 24;
goto out;
}
memset(sense, 0, sizeof(sense)); memset(sense, 0, sizeof(sense));
rq->sense = sense; rq->sense = sense;
rq->sense_len = 0; rq->sense_len = 0;
rq->data = buffer;
rq->data_len = bytes;
rq->flags |= REQ_BLOCK_PC; rq->flags |= REQ_BLOCK_PC;
rq->retries = 0;
blk_execute_rq(q, bd_disk, rq, 0); blk_execute_rq(q, disk, rq, 0);
out:
err = rq->errors & 0xff; /* only 8 bit SCSI status */ err = rq->errors & 0xff; /* only 8 bit SCSI status */
if (err) { if (err) {
if (rq->sense_len && rq->sense) { if (rq->sense_len && rq->sense) {
@ -450,7 +493,7 @@ error:
blk_put_request(rq); blk_put_request(rq);
return err; return err;
} }
EXPORT_SYMBOL_GPL(sg_scsi_ioctl);
/* Send basic block requests */ /* Send basic block requests */
static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int cmd, int data) static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int cmd, int data)

View File

@ -366,6 +366,14 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
static int static int
mptsas_slave_configure(struct scsi_device *sdev) mptsas_slave_configure(struct scsi_device *sdev)
{ {
struct Scsi_Host *host = sdev->host;
MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
/*
* RAID volumes placed beyond the last expected port.
* Ignore sending sas mode pages in that case..
*/
if (sdev->channel < hd->ioc->num_ports)
sas_read_port_mode_page(sdev); sas_read_port_mode_page(sdev);
return mptscsih_slave_configure(sdev); return mptscsih_slave_configure(sdev);

View File

@ -65,6 +65,7 @@
2.26.02.005 - Fix use_sg == 0 mapping on systems with 4GB or higher. 2.26.02.005 - Fix use_sg == 0 mapping on systems with 4GB or higher.
2.26.02.006 - Fix 9550SX pchip reset timeout. 2.26.02.006 - Fix 9550SX pchip reset timeout.
Add big endian support. Add big endian support.
2.26.02.007 - Disable local interrupts during kmap/unmap_atomic().
*/ */
#include <linux/module.h> #include <linux/module.h>
@ -88,7 +89,7 @@
#include "3w-9xxx.h" #include "3w-9xxx.h"
/* Globals */ /* Globals */
#define TW_DRIVER_VERSION "2.26.02.006" #define TW_DRIVER_VERSION "2.26.02.007"
static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
static unsigned int twa_device_extension_count; static unsigned int twa_device_extension_count;
static int twa_major = -1; static int twa_major = -1;
@ -1942,9 +1943,13 @@ static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int re
} }
if (tw_dev->srb[request_id]->use_sg == 1) { if (tw_dev->srb[request_id]->use_sg == 1) {
struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; char *buf;
unsigned long flags = 0;
local_irq_save(flags);
buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length); memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length);
kunmap_atomic(buf - sg->offset, KM_IRQ0); kunmap_atomic(buf - sg->offset, KM_IRQ0);
local_irq_restore(flags);
} }
} }
} /* End twa_scsiop_execute_scsi_complete() */ } /* End twa_scsiop_execute_scsi_complete() */

View File

@ -1079,7 +1079,7 @@ config SCSI_SYM53C8XX_DMA_ADDRESSING_MODE
memory using PCI DAC cycles. memory using PCI DAC cycles.
config SCSI_SYM53C8XX_DEFAULT_TAGS config SCSI_SYM53C8XX_DEFAULT_TAGS
int "default tagged command queue depth" int "Default tagged command queue depth"
depends on SCSI_SYM53C8XX_2 depends on SCSI_SYM53C8XX_2
default "16" default "16"
help help
@ -1090,7 +1090,7 @@ config SCSI_SYM53C8XX_DEFAULT_TAGS
exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS. exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS.
config SCSI_SYM53C8XX_MAX_TAGS config SCSI_SYM53C8XX_MAX_TAGS
int "maximum number of queued commands" int "Maximum number of queued commands"
depends on SCSI_SYM53C8XX_2 depends on SCSI_SYM53C8XX_2
default "64" default "64"
help help
@ -1099,13 +1099,14 @@ config SCSI_SYM53C8XX_MAX_TAGS
possible. The driver supports up to 256 queued commands per device. possible. The driver supports up to 256 queued commands per device.
This value is used as a compiled-in hard limit. This value is used as a compiled-in hard limit.
config SCSI_SYM53C8XX_IOMAPPED config SCSI_SYM53C8XX_MMIO
bool "use port IO" bool "Use memory mapped IO"
depends on SCSI_SYM53C8XX_2 depends on SCSI_SYM53C8XX_2
default y
help help
If you say Y here, the driver will use port IO to access Memory mapped IO is faster than Port IO. Most people should
the card. This is significantly slower then using memory answer Y here, but some machines may have problems. If you have
mapped IO. Most people should answer N. to answer N here, please report the problem to the maintainer.
config SCSI_IPR config SCSI_IPR
tristate "IBM Power Linux RAID adapter support" tristate "IBM Power Linux RAID adapter support"
@ -1309,15 +1310,6 @@ config SCSI_QLOGIC_FAS
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called qlogicfas. module will be called qlogicfas.
config SCSI_QLOGIC_FC
tristate "Qlogic ISP FC SCSI support"
depends on PCI && SCSI
help
This is a driver for the QLogic ISP2100 SCSI-FCP host adapter.
To compile this driver as a module, choose M here: the
module will be called qlogicfc.
config SCSI_QLOGIC_FC_FIRMWARE config SCSI_QLOGIC_FC_FIRMWARE
bool "Include loadable firmware in driver" bool "Include loadable firmware in driver"
depends on SCSI_QLOGIC_FC depends on SCSI_QLOGIC_FC

View File

@ -78,7 +78,6 @@ obj-$(CONFIG_SCSI_NCR_Q720) += NCR_Q720_mod.o
obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o
obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o
obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o
obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o
obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/ obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/ obj-$(CONFIG_SCSI_LPFC) += lpfc/

View File

@ -149,20 +149,20 @@ static int dacmode = -1;
static int commit = -1; static int commit = -1;
module_param(nondasd, int, 0); module_param(nondasd, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on"); MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
module_param(dacmode, int, 0); module_param(dacmode, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on"); MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on");
module_param(commit, int, 0); module_param(commit, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the adapter for foreign arrays.\nThis is typically needed in systems that do not have a BIOS. 0=off, 1=on"); MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the adapter for foreign arrays.\nThis is typically needed in systems that do not have a BIOS. 0=off, 1=on");
int numacb = -1; int numacb = -1;
module_param(numacb, int, S_IRUGO|S_IWUSR); module_param(numacb, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control blocks (FIB) allocated. Valid\nvalues are 512 and down. Default is to use suggestion from Firmware."); MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control blocks (FIB) allocated. Valid values are 512 and down. Default is to use suggestion from Firmware.");
int acbsize = -1; int acbsize = -1;
module_param(acbsize, int, S_IRUGO|S_IWUSR); module_param(acbsize, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512,\n2048, 4096 and 8192. Default is to use suggestion from Firmware."); MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware.");
/** /**
* aac_get_config_status - check the adapter configuration * aac_get_config_status - check the adapter configuration
* @common: adapter to query * @common: adapter to query
@ -387,6 +387,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
struct scsi_cmnd * scsicmd; struct scsi_cmnd * scsicmd;
scsicmd = (struct scsi_cmnd *) context; scsicmd = (struct scsi_cmnd *) context;
scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies)); dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
if (fibptr == NULL) if (fibptr == NULL)
@ -453,8 +454,10 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
/* /*
* Check that the command queued to the controller * Check that the command queued to the controller
*/ */
if (status == -EINPROGRESS) if (status == -EINPROGRESS) {
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
return 0; return 0;
}
printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status); printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
aac_fib_complete(cmd_fibcontext); aac_fib_complete(cmd_fibcontext);
@ -907,9 +910,10 @@ static void io_callback(void *context, struct fib * fibptr)
u32 cid; u32 cid;
scsicmd = (struct scsi_cmnd *) context; scsicmd = (struct scsi_cmnd *) context;
scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
dev = (struct aac_dev *)scsicmd->device->host->hostdata; dev = (struct aac_dev *)scsicmd->device->host->hostdata;
cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun); cid = scmd_id(scsicmd);
if (nblank(dprintk(x))) { if (nblank(dprintk(x))) {
u64 lba; u64 lba;
@ -1151,8 +1155,10 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
/* /*
* Check that the command queued to the controller * Check that the command queued to the controller
*/ */
if (status == -EINPROGRESS) if (status == -EINPROGRESS) {
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
return 0; return 0;
}
printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status); printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
/* /*
@ -1318,8 +1324,8 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
/* /*
* Check that the command queued to the controller * Check that the command queued to the controller
*/ */
if (status == -EINPROGRESS) if (status == -EINPROGRESS) {
{ scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
return 0; return 0;
} }
@ -1341,6 +1347,7 @@ static void synchronize_callback(void *context, struct fib *fibptr)
struct scsi_cmnd *cmd; struct scsi_cmnd *cmd;
cmd = context; cmd = context;
cmd->SCp.phase = AAC_OWNER_MIDLEVEL;
dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n",
smp_processor_id(), jiffies)); smp_processor_id(), jiffies));
@ -1354,7 +1361,7 @@ static void synchronize_callback(void *context, struct fib *fibptr)
else { else {
struct scsi_device *sdev = cmd->device; struct scsi_device *sdev = cmd->device;
struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
u32 cid = ID_LUN_TO_CONTAINER(sdev->id, sdev->lun); u32 cid = sdev_id(sdev);
printk(KERN_WARNING printk(KERN_WARNING
"synchronize_callback: synchronize failed, status = %d\n", "synchronize_callback: synchronize failed, status = %d\n",
le32_to_cpu(synchronizereply->status)); le32_to_cpu(synchronizereply->status));
@ -1386,12 +1393,12 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
unsigned long flags; unsigned long flags;
/* /*
* Wait for all commands to complete to this specific * Wait for all outstanding queued commands to complete to this
* target (block). * specific target (block).
*/ */
spin_lock_irqsave(&sdev->list_lock, flags); spin_lock_irqsave(&sdev->list_lock, flags);
list_for_each_entry(cmd, &sdev->cmd_list, list) list_for_each_entry(cmd, &sdev->cmd_list, list)
if (cmd != scsicmd && cmd->serial_number != 0) { if (cmd != scsicmd && cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
++active; ++active;
break; break;
} }
@ -1434,8 +1441,10 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
/* /*
* Check that the command queued to the controller * Check that the command queued to the controller
*/ */
if (status == -EINPROGRESS) if (status == -EINPROGRESS) {
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
return 0; return 0;
}
printk(KERN_WARNING printk(KERN_WARNING
"aac_synchronize: aac_fib_send failed with status: %d.\n", status); "aac_synchronize: aac_fib_send failed with status: %d.\n", status);
@ -1458,7 +1467,6 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
struct Scsi_Host *host = scsicmd->device->host; struct Scsi_Host *host = scsicmd->device->host;
struct aac_dev *dev = (struct aac_dev *)host->hostdata; struct aac_dev *dev = (struct aac_dev *)host->hostdata;
struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev; struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
int ret;
/* /*
* If the bus, id or lun is out of range, return fail * If the bus, id or lun is out of range, return fail
@ -1466,13 +1474,14 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
* itself. * itself.
*/ */
if (scmd_id(scsicmd) != host->this_id) { if (scmd_id(scsicmd) != host->this_id) {
if ((scsicmd->device->channel == CONTAINER_CHANNEL)) { if ((scmd_channel(scsicmd) == CONTAINER_CHANNEL)) {
if( (scsicmd->device->id >= dev->maximum_num_containers) || (scsicmd->device->lun != 0)){ if((scmd_id(scsicmd) >= dev->maximum_num_containers) ||
(scsicmd->device->lun != 0)) {
scsicmd->result = DID_NO_CONNECT << 16; scsicmd->result = DID_NO_CONNECT << 16;
scsicmd->scsi_done(scsicmd); scsicmd->scsi_done(scsicmd);
return 0; return 0;
} }
cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun); cid = scmd_id(scsicmd);
/* /*
* If the target container doesn't exist, it may have * If the target container doesn't exist, it may have
@ -1548,7 +1557,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
{ {
struct inquiry_data inq_data; struct inquiry_data inq_data;
dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->device->id)); dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scmd_id(scsicmd)));
memset(&inq_data, 0, sizeof (struct inquiry_data)); memset(&inq_data, 0, sizeof (struct inquiry_data));
inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */ inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */
@ -1598,13 +1607,14 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
cp[11] = 0; cp[11] = 0;
cp[12] = 0; cp[12] = 0;
aac_internal_transfer(scsicmd, cp, 0, aac_internal_transfer(scsicmd, cp, 0,
min((unsigned int)scsicmd->cmnd[13], sizeof(cp))); min_t(size_t, scsicmd->cmnd[13], sizeof(cp)));
if (sizeof(cp) < scsicmd->cmnd[13]) { if (sizeof(cp) < scsicmd->cmnd[13]) {
unsigned int len, offset = sizeof(cp); unsigned int len, offset = sizeof(cp);
memset(cp, 0, offset); memset(cp, 0, offset);
do { do {
len = min(scsicmd->cmnd[13]-offset, sizeof(cp)); len = min_t(size_t, scsicmd->cmnd[13] - offset,
sizeof(cp));
aac_internal_transfer(scsicmd, cp, offset, len); aac_internal_transfer(scsicmd, cp, offset, len);
} while ((offset += len) < scsicmd->cmnd[13]); } while ((offset += len) < scsicmd->cmnd[13]);
} }
@ -1728,24 +1738,19 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
* containers to /dev/sd device names * containers to /dev/sd device names
*/ */
spin_unlock_irq(host->host_lock);
if (scsicmd->request->rq_disk) if (scsicmd->request->rq_disk)
strlcpy(fsa_dev_ptr[cid].devname, strlcpy(fsa_dev_ptr[cid].devname,
scsicmd->request->rq_disk->disk_name, scsicmd->request->rq_disk->disk_name,
min(sizeof(fsa_dev_ptr[cid].devname), min(sizeof(fsa_dev_ptr[cid].devname),
sizeof(scsicmd->request->rq_disk->disk_name) + 1)); sizeof(scsicmd->request->rq_disk->disk_name) + 1));
ret = aac_read(scsicmd, cid);
spin_lock_irq(host->host_lock); return aac_read(scsicmd, cid);
return ret;
case WRITE_6: case WRITE_6:
case WRITE_10: case WRITE_10:
case WRITE_12: case WRITE_12:
case WRITE_16: case WRITE_16:
spin_unlock_irq(host->host_lock); return aac_write(scsicmd, cid);
ret = aac_write(scsicmd, cid);
spin_lock_irq(host->host_lock);
return ret;
case SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE:
/* Issue FIB to tell Firmware to flush it's cache */ /* Issue FIB to tell Firmware to flush it's cache */
@ -1778,7 +1783,7 @@ static int query_disk(struct aac_dev *dev, void __user *arg)
if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk))) if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
return -EFAULT; return -EFAULT;
if (qd.cnum == -1) if (qd.cnum == -1)
qd.cnum = ID_LUN_TO_CONTAINER(qd.id, qd.lun); qd.cnum = qd.id;
else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1))
{ {
if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers) if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
@ -1890,6 +1895,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
struct scsi_cmnd *scsicmd; struct scsi_cmnd *scsicmd;
scsicmd = (struct scsi_cmnd *) context; scsicmd = (struct scsi_cmnd *) context;
scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
dev = (struct aac_dev *)scsicmd->device->host->hostdata; dev = (struct aac_dev *)scsicmd->device->host->hostdata;
if (fibptr == NULL) if (fibptr == NULL)
@ -2068,14 +2074,13 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
u32 timeout; u32 timeout;
dev = (struct aac_dev *)scsicmd->device->host->hostdata; dev = (struct aac_dev *)scsicmd->device->host->hostdata;
if (scsicmd->device->id >= dev->maximum_num_physicals || if (scmd_id(scsicmd) >= dev->maximum_num_physicals ||
scsicmd->device->lun > 7) { scsicmd->device->lun > 7) {
scsicmd->result = DID_NO_CONNECT << 16; scsicmd->result = DID_NO_CONNECT << 16;
scsicmd->scsi_done(scsicmd); scsicmd->scsi_done(scsicmd);
return 0; return 0;
} }
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
switch(scsicmd->sc_data_direction){ switch(scsicmd->sc_data_direction){
case DMA_TO_DEVICE: case DMA_TO_DEVICE:
flag = SRB_DataOut; flag = SRB_DataOut;
@ -2103,8 +2108,8 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
srbcmd = (struct aac_srb*) fib_data(cmd_fibcontext); srbcmd = (struct aac_srb*) fib_data(cmd_fibcontext);
srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scsicmd->device->channel)); srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scmd_channel(scsicmd)));
srbcmd->id = cpu_to_le32(scsicmd->device->id); srbcmd->id = cpu_to_le32(scmd_id(scsicmd));
srbcmd->lun = cpu_to_le32(scsicmd->device->lun); srbcmd->lun = cpu_to_le32(scsicmd->device->lun);
srbcmd->flags = cpu_to_le32(flag); srbcmd->flags = cpu_to_le32(flag);
timeout = scsicmd->timeout_per_command/HZ; timeout = scsicmd->timeout_per_command/HZ;
@ -2162,6 +2167,7 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
* Check that the command queued to the controller * Check that the command queued to the controller
*/ */
if (status == -EINPROGRESS) { if (status == -EINPROGRESS) {
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
return 0; return 0;
} }
@ -2192,8 +2198,6 @@ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
scsicmd->sc_data_direction); scsicmd->sc_data_direction);
psg->count = cpu_to_le32(sg_count); psg->count = cpu_to_le32(sg_count);
byte_count = 0;
for (i = 0; i < sg_count; i++) { for (i = 0; i < sg_count; i++) {
psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg)); psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg));
psg->sg[i].count = cpu_to_le32(sg_dma_len(sg)); psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
@ -2249,18 +2253,17 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p
sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg, sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
scsicmd->sc_data_direction); scsicmd->sc_data_direction);
psg->count = cpu_to_le32(sg_count);
byte_count = 0;
for (i = 0; i < sg_count; i++) { for (i = 0; i < sg_count; i++) {
int count = sg_dma_len(sg);
addr = sg_dma_address(sg); addr = sg_dma_address(sg);
psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
psg->sg[i].addr[1] = cpu_to_le32(addr>>32); psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
psg->sg[i].count = cpu_to_le32(sg_dma_len(sg)); psg->sg[i].count = cpu_to_le32(count);
byte_count += sg_dma_len(sg); byte_count += count;
sg++; sg++;
} }
psg->count = cpu_to_le32(sg_count);
/* hba wants the size to be exact */ /* hba wants the size to be exact */
if(byte_count > scsicmd->request_bufflen){ if(byte_count > scsicmd->request_bufflen){
u32 temp = le32_to_cpu(psg->sg[i-1].count) - u32 temp = le32_to_cpu(psg->sg[i-1].count) -
@ -2275,16 +2278,15 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p
} }
} }
else if(scsicmd->request_bufflen) { else if(scsicmd->request_bufflen) {
u64 addr; scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
addr = pci_map_single(dev->pdev,
scsicmd->request_buffer, scsicmd->request_buffer,
scsicmd->request_bufflen, scsicmd->request_bufflen,
scsicmd->sc_data_direction); scsicmd->sc_data_direction);
addr = scsicmd->SCp.dma_handle;
psg->count = cpu_to_le32(1); psg->count = cpu_to_le32(1);
psg->sg[0].addr[0] = cpu_to_le32(addr & 0xffffffff); psg->sg[0].addr[0] = cpu_to_le32(addr & 0xffffffff);
psg->sg[0].addr[1] = cpu_to_le32(addr >> 32); psg->sg[0].addr[1] = cpu_to_le32(addr >> 32);
psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen); psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);
scsicmd->SCp.dma_handle = addr;
byte_count = scsicmd->request_bufflen; byte_count = scsicmd->request_bufflen;
} }
return byte_count; return byte_count;

View File

@ -10,6 +10,10 @@
* D E F I N E S * D E F I N E S
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
# define AAC_DRIVER_BUILD 2409
# define AAC_DRIVER_BRANCH "-mh1"
#endif
#define MAXIMUM_NUM_CONTAINERS 32 #define MAXIMUM_NUM_CONTAINERS 32
#define AAC_NUM_MGT_FIB 8 #define AAC_NUM_MGT_FIB 8
@ -25,7 +29,6 @@
* These macros convert from physical channels to virtual channels * These macros convert from physical channels to virtual channels
*/ */
#define CONTAINER_CHANNEL (0) #define CONTAINER_CHANNEL (0)
#define ID_LUN_TO_CONTAINER(id, lun) (id)
#define CONTAINER_TO_CHANNEL(cont) (CONTAINER_CHANNEL) #define CONTAINER_TO_CHANNEL(cont) (CONTAINER_CHANNEL)
#define CONTAINER_TO_ID(cont) (cont) #define CONTAINER_TO_ID(cont) (cont)
#define CONTAINER_TO_LUN(cont) (0) #define CONTAINER_TO_LUN(cont) (0)
@ -789,6 +792,7 @@ struct fsa_dev_info {
u64 size; u64 size;
u32 type; u32 type;
u32 config_waiting_on; u32 config_waiting_on;
unsigned long config_waiting_stamp;
u16 queue_depth; u16 queue_depth;
u8 config_needed; u8 config_needed;
u8 valid; u8 valid;
@ -1771,6 +1775,11 @@ static inline u32 cap_to_cyls(sector_t capacity, u32 divisor)
} }
struct scsi_cmnd; struct scsi_cmnd;
/* SCp.phase values */
#define AAC_OWNER_MIDLEVEL 0x101
#define AAC_OWNER_LOWLEVEL 0x102
#define AAC_OWNER_ERROR_HANDLER 0x103
#define AAC_OWNER_FIRMWARE 0x106
const char *aac_driverinfo(struct Scsi_Host *); const char *aac_driverinfo(struct Scsi_Host *);
struct fib *aac_fib_alloc(struct aac_dev *dev); struct fib *aac_fib_alloc(struct aac_dev *dev);

View File

@ -38,6 +38,8 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
@ -293,6 +295,16 @@ return_fib:
status = 0; status = 0;
} else { } else {
spin_unlock_irqrestore(&dev->fib_lock, flags); spin_unlock_irqrestore(&dev->fib_lock, flags);
/* If someone killed the AIF aacraid thread, restart it */
status = !dev->aif_thread;
if (status && dev->queues && dev->fsa_dev) {
/* Be paranoid, be very paranoid! */
kthread_stop(dev->thread);
ssleep(1);
dev->aif_thread = 0;
dev->thread = kthread_run(aac_command_thread, dev, dev->name);
ssleep(1);
}
if (f.wait) { if (f.wait) {
if(down_interruptible(&fibctx->wait_sem) < 0) { if(down_interruptible(&fibctx->wait_sem) < 0) {
status = -EINTR; status = -EINTR;

View File

@ -767,9 +767,9 @@ void aac_printf(struct aac_dev *dev, u32 val)
if (cp[length] != 0) if (cp[length] != 0)
cp[length] = 0; cp[length] = 0;
if (level == LOG_AAC_HIGH_ERROR) if (level == LOG_AAC_HIGH_ERROR)
printk(KERN_WARNING "aacraid:%s", cp); printk(KERN_WARNING "%s:%s", dev->name, cp);
else else
printk(KERN_INFO "aacraid:%s", cp); printk(KERN_INFO "%s:%s", dev->name, cp);
} }
memset(cp, 0, 256); memset(cp, 0, 256);
} }
@ -784,6 +784,7 @@ void aac_printf(struct aac_dev *dev, u32 val)
* dispatches it to the appropriate routine for handling. * dispatches it to the appropriate routine for handling.
*/ */
#define AIF_SNIFF_TIMEOUT (30*HZ)
static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
{ {
struct hw_fib * hw_fib = fibptr->hw_fib; struct hw_fib * hw_fib = fibptr->hw_fib;
@ -837,6 +838,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
if (device) { if (device) {
dev->fsa_dev[container].config_needed = CHANGE; dev->fsa_dev[container].config_needed = CHANGE;
dev->fsa_dev[container].config_waiting_on = AifEnConfigChange; dev->fsa_dev[container].config_waiting_on = AifEnConfigChange;
dev->fsa_dev[container].config_waiting_stamp = jiffies;
scsi_device_put(device); scsi_device_put(device);
} }
} }
@ -849,13 +851,15 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
if (container != (u32)-1) { if (container != (u32)-1) {
if (container >= dev->maximum_num_containers) if (container >= dev->maximum_num_containers)
break; break;
if (dev->fsa_dev[container].config_waiting_on == if ((dev->fsa_dev[container].config_waiting_on ==
le32_to_cpu(*(u32 *)aifcmd->data)) le32_to_cpu(*(u32 *)aifcmd->data)) &&
time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
dev->fsa_dev[container].config_waiting_on = 0; dev->fsa_dev[container].config_waiting_on = 0;
} else for (container = 0; } else for (container = 0;
container < dev->maximum_num_containers; ++container) { container < dev->maximum_num_containers; ++container) {
if (dev->fsa_dev[container].config_waiting_on == if ((dev->fsa_dev[container].config_waiting_on ==
le32_to_cpu(*(u32 *)aifcmd->data)) le32_to_cpu(*(u32 *)aifcmd->data)) &&
time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
dev->fsa_dev[container].config_waiting_on = 0; dev->fsa_dev[container].config_waiting_on = 0;
} }
break; break;
@ -872,6 +876,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
dev->fsa_dev[container].config_needed = ADD; dev->fsa_dev[container].config_needed = ADD;
dev->fsa_dev[container].config_waiting_on = dev->fsa_dev[container].config_waiting_on =
AifEnConfigChange; AifEnConfigChange;
dev->fsa_dev[container].config_waiting_stamp = jiffies;
break; break;
/* /*
@ -884,6 +889,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
dev->fsa_dev[container].config_needed = DELETE; dev->fsa_dev[container].config_needed = DELETE;
dev->fsa_dev[container].config_waiting_on = dev->fsa_dev[container].config_waiting_on =
AifEnConfigChange; AifEnConfigChange;
dev->fsa_dev[container].config_waiting_stamp = jiffies;
break; break;
/* /*
@ -894,11 +900,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
container = le32_to_cpu(((u32 *)aifcmd->data)[1]); container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
if (container >= dev->maximum_num_containers) if (container >= dev->maximum_num_containers)
break; break;
if (dev->fsa_dev[container].config_waiting_on) if (dev->fsa_dev[container].config_waiting_on &&
time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
break; break;
dev->fsa_dev[container].config_needed = CHANGE; dev->fsa_dev[container].config_needed = CHANGE;
dev->fsa_dev[container].config_waiting_on = dev->fsa_dev[container].config_waiting_on =
AifEnConfigChange; AifEnConfigChange;
dev->fsa_dev[container].config_waiting_stamp = jiffies;
break; break;
case AifEnConfigChange: case AifEnConfigChange:
@ -913,13 +921,15 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
if (container != (u32)-1) { if (container != (u32)-1) {
if (container >= dev->maximum_num_containers) if (container >= dev->maximum_num_containers)
break; break;
if (dev->fsa_dev[container].config_waiting_on == if ((dev->fsa_dev[container].config_waiting_on ==
le32_to_cpu(*(u32 *)aifcmd->data)) le32_to_cpu(*(u32 *)aifcmd->data)) &&
time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
dev->fsa_dev[container].config_waiting_on = 0; dev->fsa_dev[container].config_waiting_on = 0;
} else for (container = 0; } else for (container = 0;
container < dev->maximum_num_containers; ++container) { container < dev->maximum_num_containers; ++container) {
if (dev->fsa_dev[container].config_waiting_on == if ((dev->fsa_dev[container].config_waiting_on ==
le32_to_cpu(*(u32 *)aifcmd->data)) le32_to_cpu(*(u32 *)aifcmd->data)) &&
time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
dev->fsa_dev[container].config_waiting_on = 0; dev->fsa_dev[container].config_waiting_on = 0;
} }
break; break;
@ -946,6 +956,8 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
dev->fsa_dev[container].config_waiting_on = dev->fsa_dev[container].config_waiting_on =
AifEnContainerChange; AifEnContainerChange;
dev->fsa_dev[container].config_needed = ADD; dev->fsa_dev[container].config_needed = ADD;
dev->fsa_dev[container].config_waiting_stamp =
jiffies;
} }
} }
if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero)) if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
@ -961,6 +973,8 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
dev->fsa_dev[container].config_waiting_on = dev->fsa_dev[container].config_waiting_on =
AifEnContainerChange; AifEnContainerChange;
dev->fsa_dev[container].config_needed = DELETE; dev->fsa_dev[container].config_needed = DELETE;
dev->fsa_dev[container].config_waiting_stamp =
jiffies;
} }
} }
break; break;
@ -969,8 +983,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
device_config_needed = NOTHING; device_config_needed = NOTHING;
for (container = 0; container < dev->maximum_num_containers; for (container = 0; container < dev->maximum_num_containers;
++container) { ++container) {
if ((dev->fsa_dev[container].config_waiting_on == 0) if ((dev->fsa_dev[container].config_waiting_on == 0) &&
&& (dev->fsa_dev[container].config_needed != NOTHING)) { (dev->fsa_dev[container].config_needed != NOTHING) &&
time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) {
device_config_needed = device_config_needed =
dev->fsa_dev[container].config_needed; dev->fsa_dev[container].config_needed;
dev->fsa_dev[container].config_needed = NOTHING; dev->fsa_dev[container].config_needed = NOTHING;

View File

@ -27,12 +27,6 @@
* Abstract: Linux Driver entry module for Adaptec RAID Array Controller * Abstract: Linux Driver entry module for Adaptec RAID Array Controller
*/ */
#define AAC_DRIVER_VERSION "1.1-4"
#ifndef AAC_DRIVER_BRANCH
#define AAC_DRIVER_BRANCH ""
#endif
#define AAC_DRIVER_BUILD_DATE __DATE__ " " __TIME__
#define AAC_DRIVERNAME "aacraid"
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
@ -62,6 +56,13 @@
#include "aacraid.h" #include "aacraid.h"
#define AAC_DRIVER_VERSION "1.1-5"
#ifndef AAC_DRIVER_BRANCH
#define AAC_DRIVER_BRANCH ""
#endif
#define AAC_DRIVER_BUILD_DATE __DATE__ " " __TIME__
#define AAC_DRIVERNAME "aacraid"
#ifdef AAC_DRIVER_BUILD #ifdef AAC_DRIVER_BUILD
#define _str(x) #x #define _str(x) #x
#define str(x) _str(x) #define str(x) _str(x)
@ -73,7 +74,7 @@
MODULE_AUTHOR("Red Hat Inc and Adaptec"); MODULE_AUTHOR("Red Hat Inc and Adaptec");
MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, " MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, "
"Adaptec Advanced Raid Products, " "Adaptec Advanced Raid Products, "
"and HP NetRAID-4M SCSI driver"); "HP NetRAID-4M, IBM ServeRAID & ICP SCSI driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(AAC_DRIVER_FULL_VERSION); MODULE_VERSION(AAC_DRIVER_FULL_VERSION);
@ -243,6 +244,7 @@ static struct aac_driver_ident aac_drivers[] = {
static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{ {
cmd->scsi_done = done; cmd->scsi_done = done;
cmd->SCp.phase = AAC_OWNER_LOWLEVEL;
return (aac_scsi_cmd(cmd) ? FAILED : 0); return (aac_scsi_cmd(cmd) ? FAILED : 0);
} }
@ -471,7 +473,8 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
__shost_for_each_device(dev, host) { __shost_for_each_device(dev, host) {
spin_lock_irqsave(&dev->list_lock, flags); spin_lock_irqsave(&dev->list_lock, flags);
list_for_each_entry(command, &dev->cmd_list, list) { list_for_each_entry(command, &dev->cmd_list, list) {
if (command->serial_number) { if ((command != cmd) &&
(command->SCp.phase == AAC_OWNER_FIRMWARE)) {
active++; active++;
break; break;
} }
@ -569,12 +572,12 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
f = compat_alloc_user_space(sizeof(*f)); f = compat_alloc_user_space(sizeof(*f));
ret = 0; ret = 0;
if (clear_user(f, sizeof(*f) != sizeof(*f))) if (clear_user(f, sizeof(*f)) != sizeof(*f))
ret = -EFAULT; ret = -EFAULT;
if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32))) if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32)))
ret = -EFAULT; ret = -EFAULT;
if (!ret) if (!ret)
ret = aac_do_ioctl(dev, cmd, (void __user *)arg); ret = aac_do_ioctl(dev, cmd, f);
break; break;
} }
@ -687,6 +690,18 @@ static ssize_t aac_show_serial_number(struct class_device *class_dev,
return len; return len;
} }
static ssize_t aac_show_max_channel(struct class_device *class_dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n",
class_to_shost(class_dev)->max_channel);
}
static ssize_t aac_show_max_id(struct class_device *class_dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n",
class_to_shost(class_dev)->max_id);
}
static struct class_device_attribute aac_model = { static struct class_device_attribute aac_model = {
.attr = { .attr = {
@ -730,6 +745,20 @@ static struct class_device_attribute aac_serial_number = {
}, },
.show = aac_show_serial_number, .show = aac_show_serial_number,
}; };
static struct class_device_attribute aac_max_channel = {
.attr = {
.name = "max_channel",
.mode = S_IRUGO,
},
.show = aac_show_max_channel,
};
static struct class_device_attribute aac_max_id = {
.attr = {
.name = "max_id",
.mode = S_IRUGO,
},
.show = aac_show_max_id,
};
static struct class_device_attribute *aac_attrs[] = { static struct class_device_attribute *aac_attrs[] = {
&aac_model, &aac_model,
@ -738,6 +767,8 @@ static struct class_device_attribute *aac_attrs[] = {
&aac_monitor_version, &aac_monitor_version,
&aac_bios_version, &aac_bios_version,
&aac_serial_number, &aac_serial_number,
&aac_max_channel,
&aac_max_id,
NULL NULL
}; };
@ -775,6 +806,7 @@ static struct scsi_host_template aac_driver_template = {
.cmd_per_lun = AAC_NUM_IO_FIB, .cmd_per_lun = AAC_NUM_IO_FIB,
#endif #endif
.use_clustering = ENABLE_CLUSTERING, .use_clustering = ENABLE_CLUSTERING,
.emulated = 1,
}; };
@ -798,10 +830,11 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
error = pci_enable_device(pdev); error = pci_enable_device(pdev);
if (error) if (error)
goto out; goto out;
error = -ENODEV;
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
goto out; goto out_disable_pdev;
/* /*
* If the quirk31 bit is set, the adapter needs adapter * If the quirk31 bit is set, the adapter needs adapter
* to driver communication memory to be allocated below 2gig * to driver communication memory to be allocated below 2gig
@ -809,7 +842,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
if (pci_set_dma_mask(pdev, DMA_31BIT_MASK) || if (pci_set_dma_mask(pdev, DMA_31BIT_MASK) ||
pci_set_consistent_dma_mask(pdev, DMA_31BIT_MASK)) pci_set_consistent_dma_mask(pdev, DMA_31BIT_MASK))
goto out; goto out_disable_pdev;
pci_set_master(pdev); pci_set_master(pdev);
@ -904,9 +937,9 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
* physical channels are address by their actual physical number+1 * physical channels are address by their actual physical number+1
*/ */
if (aac->nondasd_support == 1) if (aac->nondasd_support == 1)
shost->max_channel = aac->maximum_num_channels + 1; shost->max_channel = aac->maximum_num_channels;
else else
shost->max_channel = 1; shost->max_channel = 0;
aac_get_config_status(aac); aac_get_config_status(aac);
aac_get_containers(aac); aac_get_containers(aac);
@ -1020,6 +1053,7 @@ static int __init aac_init(void)
static void __exit aac_exit(void) static void __exit aac_exit(void)
{ {
if (aac_cfg_major > -1)
unregister_chrdev(aac_cfg_major, "aac"); unregister_chrdev(aac_cfg_major, "aac");
pci_unregister_driver(&aac_pci_driver); pci_unregister_driver(&aac_pci_driver);
} }

View File

@ -183,7 +183,7 @@ static int rkt_sync_cmd(struct aac_dev *dev, u32 command,
/* /*
* Yield the processor in case we are slow * Yield the processor in case we are slow
*/ */
schedule_timeout_uninterruptible(1); msleep(1);
} }
if (ok != 1) { if (ok != 1) {
/* /*
@ -343,7 +343,7 @@ static int aac_rkt_check_health(struct aac_dev *dev)
NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL);
pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS), pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
post, paddr); post, paddr);
if ((buffer[0] == '0') && (buffer[1] == 'x')) { if ((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X'))) {
ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10); ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10);
ret <<= 4; ret <<= 4;
ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10); ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10);

View File

@ -183,7 +183,7 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
/* /*
* Yield the processor in case we are slow * Yield the processor in case we are slow
*/ */
schedule_timeout_uninterruptible(1); msleep(1);
} }
if (ok != 1) { if (ok != 1) {
/* /*
@ -342,7 +342,7 @@ static int aac_rx_check_health(struct aac_dev *dev)
NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL);
pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS), pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
post, paddr); post, paddr);
if ((buffer[0] == '0') && (buffer[1] == 'x')) { if ((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X'))) {
ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10); ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10);
ret <<= 4; ret <<= 4;
ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10); ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10);

View File

@ -189,7 +189,7 @@ static int sa_sync_cmd(struct aac_dev *dev, u32 command,
ok = 1; ok = 1;
break; break;
} }
schedule_timeout_uninterruptible(1); msleep(1);
} }
if (ok != 1) if (ok != 1)

View File

@ -372,7 +372,7 @@ typedef enum {
AHD_CURRENT_SENSING = 0x40000, AHD_CURRENT_SENSING = 0x40000,
AHD_SCB_CONFIG_USED = 0x80000,/* No SEEPROM but SCB had info. */ AHD_SCB_CONFIG_USED = 0x80000,/* No SEEPROM but SCB had info. */
AHD_HP_BOARD = 0x100000, AHD_HP_BOARD = 0x100000,
AHD_RESET_POLL_ACTIVE = 0x200000, AHD_BUS_RESET_ACTIVE = 0x200000,
AHD_UPDATE_PEND_CMDS = 0x400000, AHD_UPDATE_PEND_CMDS = 0x400000,
AHD_RUNNING_QOUTFIFO = 0x800000, AHD_RUNNING_QOUTFIFO = 0x800000,
AHD_HAD_FIRST_SEL = 0x1000000 AHD_HAD_FIRST_SEL = 0x1000000
@ -589,7 +589,7 @@ typedef enum {
SCB_PACKETIZED = 0x00800, SCB_PACKETIZED = 0x00800,
SCB_EXPECT_PPR_BUSFREE = 0x01000, SCB_EXPECT_PPR_BUSFREE = 0x01000,
SCB_PKT_SENSE = 0x02000, SCB_PKT_SENSE = 0x02000,
SCB_CMDPHASE_ABORT = 0x04000, SCB_EXTERNAL_RESET = 0x04000,/* Device was reset externally */
SCB_ON_COL_LIST = 0x08000, SCB_ON_COL_LIST = 0x08000,
SCB_SILENT = 0x10000 /* SCB_SILENT = 0x10000 /*
* Be quiet about transmission type * Be quiet about transmission type

View File

@ -207,7 +207,6 @@ static void ahd_add_scb_to_free_list(struct ahd_softc *ahd,
static u_int ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid, static u_int ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid,
u_int prev, u_int next, u_int tid); u_int prev, u_int next, u_int tid);
static void ahd_reset_current_bus(struct ahd_softc *ahd); static void ahd_reset_current_bus(struct ahd_softc *ahd);
static ahd_callback_t ahd_reset_poll;
static ahd_callback_t ahd_stat_timer; static ahd_callback_t ahd_stat_timer;
#ifdef AHD_DUMP_SEQ #ifdef AHD_DUMP_SEQ
static void ahd_dumpseq(struct ahd_softc *ahd); static void ahd_dumpseq(struct ahd_softc *ahd);
@ -1054,12 +1053,10 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
* If a target takes us into the command phase * If a target takes us into the command phase
* assume that it has been externally reset and * assume that it has been externally reset and
* has thus lost our previous packetized negotiation * has thus lost our previous packetized negotiation
* agreement. Since we have not sent an identify * agreement.
* message and may not have fully qualified the * Revert to async/narrow transfers until we
* connection, we change our command to TUR, assert * can renegotiate with the device and notify
* ATN and ABORT the task when we go to message in * the OSM about the reset.
* phase. The OSM will see the REQUEUE_REQUEST
* status and retry the command.
*/ */
scbid = ahd_get_scbptr(ahd); scbid = ahd_get_scbptr(ahd);
scb = ahd_lookup_scb(ahd, scbid); scb = ahd_lookup_scb(ahd, scbid);
@ -1086,31 +1083,15 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
ahd_set_syncrate(ahd, &devinfo, /*period*/0, ahd_set_syncrate(ahd, &devinfo, /*period*/0,
/*offset*/0, /*ppr_options*/0, /*offset*/0, /*ppr_options*/0,
AHD_TRANS_ACTIVE, /*paused*/TRUE); AHD_TRANS_ACTIVE, /*paused*/TRUE);
ahd_outb(ahd, SCB_CDB_STORE, 0); scb->flags |= SCB_EXTERNAL_RESET;
ahd_outb(ahd, SCB_CDB_STORE+1, 0);
ahd_outb(ahd, SCB_CDB_STORE+2, 0);
ahd_outb(ahd, SCB_CDB_STORE+3, 0);
ahd_outb(ahd, SCB_CDB_STORE+4, 0);
ahd_outb(ahd, SCB_CDB_STORE+5, 0);
ahd_outb(ahd, SCB_CDB_LEN, 6);
scb->hscb->control &= ~(TAG_ENB|SCB_TAG_TYPE);
scb->hscb->control |= MK_MESSAGE;
ahd_outb(ahd, SCB_CONTROL, scb->hscb->control);
ahd_outb(ahd, MSG_OUT, HOST_MSG);
ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid);
/*
* The lun is 0, regardless of the SCB's lun
* as we have not sent an identify message.
*/
ahd_outb(ahd, SAVED_LUN, 0);
ahd_outb(ahd, SEQ_FLAGS, 0);
ahd_assert_atn(ahd);
scb->flags &= ~SCB_PACKETIZED;
scb->flags |= SCB_ABORT|SCB_CMDPHASE_ABORT;
ahd_freeze_devq(ahd, scb); ahd_freeze_devq(ahd, scb);
ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
ahd_freeze_scb(scb); ahd_freeze_scb(scb);
/* Notify XPT */
ahd_send_async(ahd, devinfo.channel, devinfo.target,
CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
/* /*
* Allow the sequencer to continue with * Allow the sequencer to continue with
* non-pack processing. * non-pack processing.
@ -1534,6 +1515,18 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
lqistat1 = ahd_inb(ahd, LQISTAT1); lqistat1 = ahd_inb(ahd, LQISTAT1);
lqostat0 = ahd_inb(ahd, LQOSTAT0); lqostat0 = ahd_inb(ahd, LQOSTAT0);
busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME; busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME;
/*
* Ignore external resets after a bus reset.
*/
if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE))
return;
/*
* Clear bus reset flag
*/
ahd->flags &= ~AHD_BUS_RESET_ACTIVE;
if ((status0 & (SELDI|SELDO)) != 0) { if ((status0 & (SELDI|SELDO)) != 0) {
u_int simode0; u_int simode0;
@ -2207,22 +2200,6 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
if (sent_msg == MSG_ABORT_TAG) if (sent_msg == MSG_ABORT_TAG)
tag = SCB_GET_TAG(scb); tag = SCB_GET_TAG(scb);
if ((scb->flags & SCB_CMDPHASE_ABORT) != 0) {
/*
* This abort is in response to an
* unexpected switch to command phase
* for a packetized connection. Since
* the identify message was never sent,
* "saved lun" is 0. We really want to
* abort only the SCB that encountered
* this error, which could have a different
* lun. The SCB will be retried so the OS
* will see the UA after renegotiating to
* packetized.
*/
tag = SCB_GET_TAG(scb);
saved_lun = scb->hscb->lun;
}
found = ahd_abort_scbs(ahd, target, 'A', saved_lun, found = ahd_abort_scbs(ahd, target, 'A', saved_lun,
tag, ROLE_INITIATOR, tag, ROLE_INITIATOR,
CAM_REQ_ABORTED); CAM_REQ_ABORTED);
@ -7847,6 +7824,17 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
int found; int found;
u_int fifo; u_int fifo;
u_int next_fifo; u_int next_fifo;
uint8_t scsiseq;
/*
* Check if the last bus reset is cleared
*/
if (ahd->flags & AHD_BUS_RESET_ACTIVE) {
printf("%s: bus reset still active\n",
ahd_name(ahd));
return 0;
}
ahd->flags |= AHD_BUS_RESET_ACTIVE;
ahd->pending_device = NULL; ahd->pending_device = NULL;
@ -7860,6 +7848,12 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
/* Make sure the sequencer is in a safe location. */ /* Make sure the sequencer is in a safe location. */
ahd_clear_critical_section(ahd); ahd_clear_critical_section(ahd);
/*
* Run our command complete fifos to ensure that we perform
* completion processing on any commands that 'completed'
* before the reset occurred.
*/
ahd_run_qoutfifo(ahd);
#ifdef AHD_TARGET_MODE #ifdef AHD_TARGET_MODE
if ((ahd->flags & AHD_TARGETROLE) != 0) { if ((ahd->flags & AHD_TARGETROLE) != 0) {
ahd_run_tqinfifo(ahd, /*paused*/TRUE); ahd_run_tqinfifo(ahd, /*paused*/TRUE);
@ -7924,30 +7918,14 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
ahd_clear_fifo(ahd, 1); ahd_clear_fifo(ahd, 1);
/* /*
* Revert to async/narrow transfers until we renegotiate. * Reenable selections
*/ */
ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST);
scsiseq = ahd_inb(ahd, SCSISEQ_TEMPLATE);
ahd_outb(ahd, SCSISEQ1, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP));
max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7; max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7;
for (target = 0; target <= max_scsiid; target++) {
if (ahd->enabled_targets[target] == NULL)
continue;
for (initiator = 0; initiator <= max_scsiid; initiator++) {
struct ahd_devinfo devinfo;
ahd_compile_devinfo(&devinfo, target, initiator,
CAM_LUN_WILDCARD,
'A', ROLE_UNKNOWN);
ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
AHD_TRANS_CUR, /*paused*/TRUE);
ahd_set_syncrate(ahd, &devinfo, /*period*/0,
/*offset*/0, /*ppr_options*/0,
AHD_TRANS_CUR, /*paused*/TRUE);
}
}
#ifdef AHD_TARGET_MODE #ifdef AHD_TARGET_MODE
max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7;
/* /*
* Send an immediate notify ccb to all target more peripheral * Send an immediate notify ccb to all target more peripheral
* drivers affected by this action. * drivers affected by this action.
@ -7975,53 +7953,33 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
/* Notify the XPT that a bus reset occurred */ /* Notify the XPT that a bus reset occurred */
ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD,
CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
ahd_restart(ahd);
/* /*
* Freeze the SIMQ until our poller can determine that * Revert to async/narrow transfers until we renegotiate.
* the bus reset has really gone away. We set the initial
* timer to 0 to have the check performed as soon as possible
* from the timer context.
*/ */
if ((ahd->flags & AHD_RESET_POLL_ACTIVE) == 0) { for (target = 0; target <= max_scsiid; target++) {
ahd->flags |= AHD_RESET_POLL_ACTIVE;
ahd_freeze_simq(ahd); if (ahd->enabled_targets[target] == NULL)
ahd_timer_reset(&ahd->reset_timer, 0, ahd_reset_poll, ahd); continue;
for (initiator = 0; initiator <= max_scsiid; initiator++) {
struct ahd_devinfo devinfo;
ahd_compile_devinfo(&devinfo, target, initiator,
CAM_LUN_WILDCARD,
'A', ROLE_UNKNOWN);
ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
AHD_TRANS_CUR, /*paused*/TRUE);
ahd_set_syncrate(ahd, &devinfo, /*period*/0,
/*offset*/0, /*ppr_options*/0,
AHD_TRANS_CUR, /*paused*/TRUE);
} }
}
ahd_restart(ahd);
return (found); return (found);
} }
#define AHD_RESET_POLL_US 1000
static void
ahd_reset_poll(void *arg)
{
struct ahd_softc *ahd = arg;
u_int scsiseq1;
u_long s;
ahd_lock(ahd, &s);
ahd_pause(ahd);
ahd_update_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI);
if ((ahd_inb(ahd, SSTAT1) & SCSIRSTI) != 0) {
ahd_timer_reset(&ahd->reset_timer, AHD_RESET_POLL_US,
ahd_reset_poll, ahd);
ahd_unpause(ahd);
ahd_unlock(ahd, &s);
return;
}
/* Reset is now low. Complete chip reinitialization. */
ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST);
scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE);
ahd_outb(ahd, SCSISEQ1, scsiseq1 & (ENSELI|ENRSELI|ENAUTOATNP));
ahd_unpause(ahd);
ahd->flags &= ~AHD_RESET_POLL_ACTIVE;
ahd_unlock(ahd, &s);
ahd_release_simq(ahd);
}
/**************************** Statistics Processing ***************************/ /**************************** Statistics Processing ***************************/
static void static void
ahd_stat_timer(void *arg) ahd_stat_timer(void *arg)

View File

@ -782,6 +782,7 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd)
{ {
struct ahd_softc *ahd; struct ahd_softc *ahd;
int found; int found;
unsigned long flags;
ahd = *(struct ahd_softc **)cmd->device->host->hostdata; ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
#ifdef AHD_DEBUG #ifdef AHD_DEBUG
@ -789,8 +790,11 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd)
printf("%s: Bus reset called for cmd %p\n", printf("%s: Bus reset called for cmd %p\n",
ahd_name(ahd), cmd); ahd_name(ahd), cmd);
#endif #endif
ahd_lock(ahd, &flags);
found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A', found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A',
/*initiate reset*/TRUE); /*initiate reset*/TRUE);
ahd_unlock(ahd, &flags);
if (bootverbose) if (bootverbose)
printf("%s: SCSI bus reset delivered. " printf("%s: SCSI bus reset delivered. "

View File

@ -168,7 +168,7 @@ static void release_event_pool(struct event_pool *pool,
++in_use; ++in_use;
if (pool->events[i].ext_list) { if (pool->events[i].ext_list) {
dma_free_coherent(hostdata->dev, dma_free_coherent(hostdata->dev,
SG_ALL * sizeof(struct memory_descriptor), SG_ALL * sizeof(struct srp_direct_buf),
pool->events[i].ext_list, pool->events[i].ext_list,
pool->events[i].ext_list_token); pool->events[i].ext_list_token);
} }
@ -284,40 +284,37 @@ static void set_srp_direction(struct scsi_cmnd *cmd,
struct srp_cmd *srp_cmd, struct srp_cmd *srp_cmd,
int numbuf) int numbuf)
{ {
u8 fmt;
if (numbuf == 0) if (numbuf == 0)
return; return;
if (numbuf == 1) { if (numbuf == 1)
fmt = SRP_DATA_DESC_DIRECT;
else {
fmt = SRP_DATA_DESC_INDIRECT;
numbuf = min(numbuf, MAX_INDIRECT_BUFS);
if (cmd->sc_data_direction == DMA_TO_DEVICE) if (cmd->sc_data_direction == DMA_TO_DEVICE)
srp_cmd->data_out_format = SRP_DIRECT_BUFFER; srp_cmd->data_out_desc_cnt = numbuf;
else else
srp_cmd->data_in_format = SRP_DIRECT_BUFFER; srp_cmd->data_in_desc_cnt = numbuf;
} else {
if (cmd->sc_data_direction == DMA_TO_DEVICE) {
srp_cmd->data_out_format = SRP_INDIRECT_BUFFER;
srp_cmd->data_out_count =
numbuf < MAX_INDIRECT_BUFS ?
numbuf: MAX_INDIRECT_BUFS;
} else {
srp_cmd->data_in_format = SRP_INDIRECT_BUFFER;
srp_cmd->data_in_count =
numbuf < MAX_INDIRECT_BUFS ?
numbuf: MAX_INDIRECT_BUFS;
}
} }
if (cmd->sc_data_direction == DMA_TO_DEVICE)
srp_cmd->buf_fmt = fmt << 4;
else
srp_cmd->buf_fmt = fmt;
} }
static void unmap_sg_list(int num_entries, static void unmap_sg_list(int num_entries,
struct device *dev, struct device *dev,
struct memory_descriptor *md) struct srp_direct_buf *md)
{ {
int i; int i;
for (i = 0; i < num_entries; ++i) { for (i = 0; i < num_entries; ++i)
dma_unmap_single(dev, dma_unmap_single(dev, md[i].va, md[i].len, DMA_BIDIRECTIONAL);
md[i].virtual_address,
md[i].length, DMA_BIDIRECTIONAL);
}
} }
/** /**
@ -330,23 +327,26 @@ static void unmap_cmd_data(struct srp_cmd *cmd,
struct srp_event_struct *evt_struct, struct srp_event_struct *evt_struct,
struct device *dev) struct device *dev)
{ {
if ((cmd->data_out_format == SRP_NO_BUFFER) && u8 out_fmt, in_fmt;
(cmd->data_in_format == SRP_NO_BUFFER))
out_fmt = cmd->buf_fmt >> 4;
in_fmt = cmd->buf_fmt & ((1U << 4) - 1);
if (out_fmt == SRP_NO_DATA_DESC && in_fmt == SRP_NO_DATA_DESC)
return; return;
else if ((cmd->data_out_format == SRP_DIRECT_BUFFER) || else if (out_fmt == SRP_DATA_DESC_DIRECT ||
(cmd->data_in_format == SRP_DIRECT_BUFFER)) { in_fmt == SRP_DATA_DESC_DIRECT) {
struct memory_descriptor *data = struct srp_direct_buf *data =
(struct memory_descriptor *)cmd->additional_data; (struct srp_direct_buf *) cmd->add_data;
dma_unmap_single(dev, data->virtual_address, data->length, dma_unmap_single(dev, data->va, data->len, DMA_BIDIRECTIONAL);
DMA_BIDIRECTIONAL);
} else { } else {
struct indirect_descriptor *indirect = struct srp_indirect_buf *indirect =
(struct indirect_descriptor *)cmd->additional_data; (struct srp_indirect_buf *) cmd->add_data;
int num_mapped = indirect->head.length / int num_mapped = indirect->table_desc.len /
sizeof(indirect->list[0]); sizeof(struct srp_direct_buf);
if (num_mapped <= MAX_INDIRECT_BUFS) { if (num_mapped <= MAX_INDIRECT_BUFS) {
unmap_sg_list(num_mapped, dev, &indirect->list[0]); unmap_sg_list(num_mapped, dev, &indirect->desc_list[0]);
return; return;
} }
@ -356,17 +356,17 @@ static void unmap_cmd_data(struct srp_cmd *cmd,
static int map_sg_list(int num_entries, static int map_sg_list(int num_entries,
struct scatterlist *sg, struct scatterlist *sg,
struct memory_descriptor *md) struct srp_direct_buf *md)
{ {
int i; int i;
u64 total_length = 0; u64 total_length = 0;
for (i = 0; i < num_entries; ++i) { for (i = 0; i < num_entries; ++i) {
struct memory_descriptor *descr = md + i; struct srp_direct_buf *descr = md + i;
struct scatterlist *sg_entry = &sg[i]; struct scatterlist *sg_entry = &sg[i];
descr->virtual_address = sg_dma_address(sg_entry); descr->va = sg_dma_address(sg_entry);
descr->length = sg_dma_len(sg_entry); descr->len = sg_dma_len(sg_entry);
descr->memory_handle = 0; descr->key = 0;
total_length += sg_dma_len(sg_entry); total_length += sg_dma_len(sg_entry);
} }
return total_length; return total_length;
@ -389,10 +389,10 @@ static int map_sg_data(struct scsi_cmnd *cmd,
int sg_mapped; int sg_mapped;
u64 total_length = 0; u64 total_length = 0;
struct scatterlist *sg = cmd->request_buffer; struct scatterlist *sg = cmd->request_buffer;
struct memory_descriptor *data = struct srp_direct_buf *data =
(struct memory_descriptor *)srp_cmd->additional_data; (struct srp_direct_buf *) srp_cmd->add_data;
struct indirect_descriptor *indirect = struct srp_indirect_buf *indirect =
(struct indirect_descriptor *)data; (struct srp_indirect_buf *) data;
sg_mapped = dma_map_sg(dev, sg, cmd->use_sg, DMA_BIDIRECTIONAL); sg_mapped = dma_map_sg(dev, sg, cmd->use_sg, DMA_BIDIRECTIONAL);
@ -403,9 +403,9 @@ static int map_sg_data(struct scsi_cmnd *cmd,
/* special case; we can use a single direct descriptor */ /* special case; we can use a single direct descriptor */
if (sg_mapped == 1) { if (sg_mapped == 1) {
data->virtual_address = sg_dma_address(&sg[0]); data->va = sg_dma_address(&sg[0]);
data->length = sg_dma_len(&sg[0]); data->len = sg_dma_len(&sg[0]);
data->memory_handle = 0; data->key = 0;
return 1; return 1;
} }
@ -416,21 +416,22 @@ static int map_sg_data(struct scsi_cmnd *cmd,
return 0; return 0;
} }
indirect->head.virtual_address = 0; indirect->table_desc.va = 0;
indirect->head.length = sg_mapped * sizeof(indirect->list[0]); indirect->table_desc.len = sg_mapped * sizeof(struct srp_direct_buf);
indirect->head.memory_handle = 0; indirect->table_desc.key = 0;
if (sg_mapped <= MAX_INDIRECT_BUFS) { if (sg_mapped <= MAX_INDIRECT_BUFS) {
total_length = map_sg_list(sg_mapped, sg, &indirect->list[0]); total_length = map_sg_list(sg_mapped, sg,
indirect->total_length = total_length; &indirect->desc_list[0]);
indirect->len = total_length;
return 1; return 1;
} }
/* get indirect table */ /* get indirect table */
if (!evt_struct->ext_list) { if (!evt_struct->ext_list) {
evt_struct->ext_list =(struct memory_descriptor*) evt_struct->ext_list = (struct srp_direct_buf *)
dma_alloc_coherent(dev, dma_alloc_coherent(dev,
SG_ALL * sizeof(struct memory_descriptor), SG_ALL * sizeof(struct srp_direct_buf),
&evt_struct->ext_list_token, 0); &evt_struct->ext_list_token, 0);
if (!evt_struct->ext_list) { if (!evt_struct->ext_list) {
printk(KERN_ERR printk(KERN_ERR
@ -442,11 +443,11 @@ static int map_sg_data(struct scsi_cmnd *cmd,
total_length = map_sg_list(sg_mapped, sg, evt_struct->ext_list); total_length = map_sg_list(sg_mapped, sg, evt_struct->ext_list);
indirect->total_length = total_length; indirect->len = total_length;
indirect->head.virtual_address = evt_struct->ext_list_token; indirect->table_desc.va = evt_struct->ext_list_token;
indirect->head.length = sg_mapped * sizeof(indirect->list[0]); indirect->table_desc.len = sg_mapped * sizeof(indirect->desc_list[0]);
memcpy(indirect->list, evt_struct->ext_list, memcpy(indirect->desc_list, evt_struct->ext_list,
MAX_INDIRECT_BUFS * sizeof(struct memory_descriptor)); MAX_INDIRECT_BUFS * sizeof(struct srp_direct_buf));
return 1; return 1;
} }
@ -463,20 +464,20 @@ static int map_sg_data(struct scsi_cmnd *cmd,
static int map_single_data(struct scsi_cmnd *cmd, static int map_single_data(struct scsi_cmnd *cmd,
struct srp_cmd *srp_cmd, struct device *dev) struct srp_cmd *srp_cmd, struct device *dev)
{ {
struct memory_descriptor *data = struct srp_direct_buf *data =
(struct memory_descriptor *)srp_cmd->additional_data; (struct srp_direct_buf *) srp_cmd->add_data;
data->virtual_address = data->va =
dma_map_single(dev, cmd->request_buffer, dma_map_single(dev, cmd->request_buffer,
cmd->request_bufflen, cmd->request_bufflen,
DMA_BIDIRECTIONAL); DMA_BIDIRECTIONAL);
if (dma_mapping_error(data->virtual_address)) { if (dma_mapping_error(data->va)) {
printk(KERN_ERR printk(KERN_ERR
"ibmvscsi: Unable to map request_buffer for command!\n"); "ibmvscsi: Unable to map request_buffer for command!\n");
return 0; return 0;
} }
data->length = cmd->request_bufflen; data->len = cmd->request_bufflen;
data->memory_handle = 0; data->key = 0;
set_srp_direction(cmd, srp_cmd, 1); set_srp_direction(cmd, srp_cmd, 1);
@ -548,7 +549,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
/* Copy the IU into the transfer area */ /* Copy the IU into the transfer area */
*evt_struct->xfer_iu = evt_struct->iu; *evt_struct->xfer_iu = evt_struct->iu;
evt_struct->xfer_iu->srp.generic.tag = (u64)evt_struct; evt_struct->xfer_iu->srp.rsp.tag = (u64)evt_struct;
/* Add this to the sent list. We need to do this /* Add this to the sent list. We need to do this
* before we actually send * before we actually send
@ -586,27 +587,27 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp; struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp;
struct scsi_cmnd *cmnd = evt_struct->cmnd; struct scsi_cmnd *cmnd = evt_struct->cmnd;
if (unlikely(rsp->type != SRP_RSP_TYPE)) { if (unlikely(rsp->opcode != SRP_RSP)) {
if (printk_ratelimit()) if (printk_ratelimit())
printk(KERN_WARNING printk(KERN_WARNING
"ibmvscsi: bad SRP RSP type %d\n", "ibmvscsi: bad SRP RSP type %d\n",
rsp->type); rsp->opcode);
} }
if (cmnd) { if (cmnd) {
cmnd->result = rsp->status; cmnd->result = rsp->status;
if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION) if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
memcpy(cmnd->sense_buffer, memcpy(cmnd->sense_buffer,
rsp->sense_and_response_data, rsp->data,
rsp->sense_data_list_length); rsp->sense_data_len);
unmap_cmd_data(&evt_struct->iu.srp.cmd, unmap_cmd_data(&evt_struct->iu.srp.cmd,
evt_struct, evt_struct,
evt_struct->hostdata->dev); evt_struct->hostdata->dev);
if (rsp->doover) if (rsp->flags & SRP_RSP_FLAG_DOOVER)
cmnd->resid = rsp->data_out_residual_count; cmnd->resid = rsp->data_out_res_cnt;
else if (rsp->diover) else if (rsp->flags & SRP_RSP_FLAG_DIOVER)
cmnd->resid = rsp->data_in_residual_count; cmnd->resid = rsp->data_in_res_cnt;
} }
if (evt_struct->cmnd_done) if (evt_struct->cmnd_done)
@ -633,10 +634,11 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
{ {
struct srp_cmd *srp_cmd; struct srp_cmd *srp_cmd;
struct srp_event_struct *evt_struct; struct srp_event_struct *evt_struct;
struct indirect_descriptor *indirect; struct srp_indirect_buf *indirect;
struct ibmvscsi_host_data *hostdata = struct ibmvscsi_host_data *hostdata =
(struct ibmvscsi_host_data *)&cmnd->device->host->hostdata; (struct ibmvscsi_host_data *)&cmnd->device->host->hostdata;
u16 lun = lun_from_dev(cmnd->device); u16 lun = lun_from_dev(cmnd->device);
u8 out_fmt, in_fmt;
evt_struct = get_event_struct(&hostdata->pool); evt_struct = get_event_struct(&hostdata->pool);
if (!evt_struct) if (!evt_struct)
@ -644,8 +646,8 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
/* Set up the actual SRP IU */ /* Set up the actual SRP IU */
srp_cmd = &evt_struct->iu.srp.cmd; srp_cmd = &evt_struct->iu.srp.cmd;
memset(srp_cmd, 0x00, sizeof(*srp_cmd)); memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
srp_cmd->type = SRP_CMD_TYPE; srp_cmd->opcode = SRP_CMD;
memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd)); memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
srp_cmd->lun = ((u64) lun) << 48; srp_cmd->lun = ((u64) lun) << 48;
@ -664,13 +666,15 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
evt_struct->cmnd_done = done; evt_struct->cmnd_done = done;
/* Fix up dma address of the buffer itself */ /* Fix up dma address of the buffer itself */
indirect = (struct indirect_descriptor *)srp_cmd->additional_data; indirect = (struct srp_indirect_buf *) srp_cmd->add_data;
if (((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) || out_fmt = srp_cmd->buf_fmt >> 4;
(srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) && in_fmt = srp_cmd->buf_fmt & ((1U << 4) - 1);
(indirect->head.virtual_address == 0)) { if ((in_fmt == SRP_DATA_DESC_INDIRECT ||
indirect->head.virtual_address = evt_struct->crq.IU_data_ptr + out_fmt == SRP_DATA_DESC_INDIRECT) &&
offsetof(struct srp_cmd, additional_data) + indirect->table_desc.va == 0) {
offsetof(struct indirect_descriptor, list); indirect->table_desc.va = evt_struct->crq.IU_data_ptr +
offsetof(struct srp_cmd, add_data) +
offsetof(struct srp_indirect_buf, desc_list);
} }
return ibmvscsi_send_srp_event(evt_struct, hostdata); return ibmvscsi_send_srp_event(evt_struct, hostdata);
@ -780,10 +784,10 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
static void login_rsp(struct srp_event_struct *evt_struct) static void login_rsp(struct srp_event_struct *evt_struct)
{ {
struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
switch (evt_struct->xfer_iu->srp.generic.type) { switch (evt_struct->xfer_iu->srp.login_rsp.opcode) {
case SRP_LOGIN_RSP_TYPE: /* it worked! */ case SRP_LOGIN_RSP: /* it worked! */
break; break;
case SRP_LOGIN_REJ_TYPE: /* refused! */ case SRP_LOGIN_REJ: /* refused! */
printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REJ reason %u\n", printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REJ reason %u\n",
evt_struct->xfer_iu->srp.login_rej.reason); evt_struct->xfer_iu->srp.login_rej.reason);
/* Login failed. */ /* Login failed. */
@ -792,7 +796,7 @@ static void login_rsp(struct srp_event_struct *evt_struct)
default: default:
printk(KERN_ERR printk(KERN_ERR
"ibmvscsi: Invalid login response typecode 0x%02x!\n", "ibmvscsi: Invalid login response typecode 0x%02x!\n",
evt_struct->xfer_iu->srp.generic.type); evt_struct->xfer_iu->srp.login_rsp.opcode);
/* Login failed. */ /* Login failed. */
atomic_set(&hostdata->request_limit, -1); atomic_set(&hostdata->request_limit, -1);
return; return;
@ -800,17 +804,17 @@ static void login_rsp(struct srp_event_struct *evt_struct)
printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n"); printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n");
if (evt_struct->xfer_iu->srp.login_rsp.request_limit_delta > if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta >
(max_requests - 2)) (max_requests - 2))
evt_struct->xfer_iu->srp.login_rsp.request_limit_delta = evt_struct->xfer_iu->srp.login_rsp.req_lim_delta =
max_requests - 2; max_requests - 2;
/* Now we know what the real request-limit is */ /* Now we know what the real request-limit is */
atomic_set(&hostdata->request_limit, atomic_set(&hostdata->request_limit,
evt_struct->xfer_iu->srp.login_rsp.request_limit_delta); evt_struct->xfer_iu->srp.login_rsp.req_lim_delta);
hostdata->host->can_queue = hostdata->host->can_queue =
evt_struct->xfer_iu->srp.login_rsp.request_limit_delta - 2; evt_struct->xfer_iu->srp.login_rsp.req_lim_delta - 2;
if (hostdata->host->can_queue < 1) { if (hostdata->host->can_queue < 1) {
printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n"); printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n");
@ -849,18 +853,19 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
login = &evt_struct->iu.srp.login_req; login = &evt_struct->iu.srp.login_req;
memset(login, 0x00, sizeof(struct srp_login_req)); memset(login, 0x00, sizeof(struct srp_login_req));
login->type = SRP_LOGIN_REQ_TYPE; login->opcode = SRP_LOGIN_REQ;
login->max_requested_initiator_to_target_iulen = sizeof(union srp_iu); login->req_it_iu_len = sizeof(union srp_iu);
login->required_buffer_formats = 0x0006; login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
spin_lock_irqsave(hostdata->host->host_lock, flags);
/* Start out with a request limit of 1, since this is negotiated in /* Start out with a request limit of 1, since this is negotiated in
* the login request we are just sending * the login request we are just sending
*/ */
atomic_set(&hostdata->request_limit, 1); atomic_set(&hostdata->request_limit, 1);
spin_lock_irqsave(hostdata->host->host_lock, flags);
rc = ibmvscsi_send_srp_event(evt_struct, hostdata); rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
spin_unlock_irqrestore(hostdata->host->host_lock, flags); spin_unlock_irqrestore(hostdata->host->host_lock, flags);
printk("ibmvscsic: sent SRP login\n");
return rc; return rc;
}; };
@ -928,13 +933,13 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
/* Set up an abort SRP command */ /* Set up an abort SRP command */
memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
tsk_mgmt->type = SRP_TSK_MGMT_TYPE; tsk_mgmt->opcode = SRP_TSK_MGMT;
tsk_mgmt->lun = ((u64) lun) << 48; tsk_mgmt->lun = ((u64) lun) << 48;
tsk_mgmt->task_mgmt_flags = 0x01; /* ABORT TASK */ tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
tsk_mgmt->managed_task_tag = (u64) found_evt; tsk_mgmt->task_tag = (u64) found_evt;
printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n", printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n",
tsk_mgmt->lun, tsk_mgmt->managed_task_tag); tsk_mgmt->lun, tsk_mgmt->task_tag);
evt->sync_srp = &srp_rsp; evt->sync_srp = &srp_rsp;
init_completion(&evt->comp); init_completion(&evt->comp);
@ -948,16 +953,16 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
wait_for_completion(&evt->comp); wait_for_completion(&evt->comp);
/* make sure we got a good response */ /* make sure we got a good response */
if (unlikely(srp_rsp.srp.generic.type != SRP_RSP_TYPE)) { if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
if (printk_ratelimit()) if (printk_ratelimit())
printk(KERN_WARNING printk(KERN_WARNING
"ibmvscsi: abort bad SRP RSP type %d\n", "ibmvscsi: abort bad SRP RSP type %d\n",
srp_rsp.srp.generic.type); srp_rsp.srp.rsp.opcode);
return FAILED; return FAILED;
} }
if (srp_rsp.srp.rsp.rspvalid) if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID)
rsp_rc = *((int *)srp_rsp.srp.rsp.sense_and_response_data); rsp_rc = *((int *)srp_rsp.srp.rsp.data);
else else
rsp_rc = srp_rsp.srp.rsp.status; rsp_rc = srp_rsp.srp.rsp.status;
@ -966,7 +971,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
printk(KERN_WARNING printk(KERN_WARNING
"ibmvscsi: abort code %d for task tag 0x%lx\n", "ibmvscsi: abort code %d for task tag 0x%lx\n",
rsp_rc, rsp_rc,
tsk_mgmt->managed_task_tag); tsk_mgmt->task_tag);
return FAILED; return FAILED;
} }
@ -987,13 +992,13 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
spin_unlock_irqrestore(hostdata->host->host_lock, flags); spin_unlock_irqrestore(hostdata->host->host_lock, flags);
printk(KERN_INFO printk(KERN_INFO
"ibmvscsi: aborted task tag 0x%lx completed\n", "ibmvscsi: aborted task tag 0x%lx completed\n",
tsk_mgmt->managed_task_tag); tsk_mgmt->task_tag);
return SUCCESS; return SUCCESS;
} }
printk(KERN_INFO printk(KERN_INFO
"ibmvscsi: successfully aborted task tag 0x%lx\n", "ibmvscsi: successfully aborted task tag 0x%lx\n",
tsk_mgmt->managed_task_tag); tsk_mgmt->task_tag);
cmd->result = (DID_ABORT << 16); cmd->result = (DID_ABORT << 16);
list_del(&found_evt->list); list_del(&found_evt->list);
@ -1040,9 +1045,9 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
/* Set up a lun reset SRP command */ /* Set up a lun reset SRP command */
memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
tsk_mgmt->type = SRP_TSK_MGMT_TYPE; tsk_mgmt->opcode = SRP_TSK_MGMT;
tsk_mgmt->lun = ((u64) lun) << 48; tsk_mgmt->lun = ((u64) lun) << 48;
tsk_mgmt->task_mgmt_flags = 0x08; /* LUN RESET */ tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n", printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n",
tsk_mgmt->lun); tsk_mgmt->lun);
@ -1059,16 +1064,16 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
wait_for_completion(&evt->comp); wait_for_completion(&evt->comp);
/* make sure we got a good response */ /* make sure we got a good response */
if (unlikely(srp_rsp.srp.generic.type != SRP_RSP_TYPE)) { if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
if (printk_ratelimit()) if (printk_ratelimit())
printk(KERN_WARNING printk(KERN_WARNING
"ibmvscsi: reset bad SRP RSP type %d\n", "ibmvscsi: reset bad SRP RSP type %d\n",
srp_rsp.srp.generic.type); srp_rsp.srp.rsp.opcode);
return FAILED; return FAILED;
} }
if (srp_rsp.srp.rsp.rspvalid) if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID)
rsp_rc = *((int *)srp_rsp.srp.rsp.sense_and_response_data); rsp_rc = *((int *)srp_rsp.srp.rsp.data);
else else
rsp_rc = srp_rsp.srp.rsp.status; rsp_rc = srp_rsp.srp.rsp.status;
@ -1076,8 +1081,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
if (printk_ratelimit()) if (printk_ratelimit())
printk(KERN_WARNING printk(KERN_WARNING
"ibmvscsi: reset code %d for task tag 0x%lx\n", "ibmvscsi: reset code %d for task tag 0x%lx\n",
rsp_rc, rsp_rc, tsk_mgmt->task_tag);
tsk_mgmt->managed_task_tag);
return FAILED; return FAILED;
} }
@ -1179,6 +1183,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
/* We need to re-setup the interpartition connection */ /* We need to re-setup the interpartition connection */
printk(KERN_INFO printk(KERN_INFO
"ibmvscsi: Re-enabling adapter!\n"); "ibmvscsi: Re-enabling adapter!\n");
atomic_set(&hostdata->request_limit, -1);
purge_requests(hostdata, DID_REQUEUE); purge_requests(hostdata, DID_REQUEUE);
if (ibmvscsi_reenable_crq_queue(&hostdata->queue, if (ibmvscsi_reenable_crq_queue(&hostdata->queue,
hostdata) == 0) hostdata) == 0)
@ -1226,7 +1231,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
} }
if (crq->format == VIOSRP_SRP_FORMAT) if (crq->format == VIOSRP_SRP_FORMAT)
atomic_add(evt_struct->xfer_iu->srp.rsp.request_limit_delta, atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta,
&hostdata->request_limit); &hostdata->request_limit);
if (evt_struct->done) if (evt_struct->done)

View File

@ -68,7 +68,7 @@ struct srp_event_struct {
void (*cmnd_done) (struct scsi_cmnd *); void (*cmnd_done) (struct scsi_cmnd *);
struct completion comp; struct completion comp;
union viosrp_iu *sync_srp; union viosrp_iu *sync_srp;
struct memory_descriptor *ext_list; struct srp_direct_buf *ext_list;
dma_addr_t ext_list_token; dma_addr_t ext_list_token;
}; };

View File

@ -34,7 +34,6 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include "ibmvscsi.h" #include "ibmvscsi.h"
#include "srp.h"
static char partition_name[97] = "UNKNOWN"; static char partition_name[97] = "UNKNOWN";
static unsigned int partition_number = -1; static unsigned int partition_number = -1;

View File

@ -1,227 +0,0 @@
/*****************************************************************************/
/* srp.h -- SCSI RDMA Protocol definitions */
/* */
/* Written By: Colin Devilbis, IBM Corporation */
/* */
/* Copyright (C) 2003 IBM Corporation */
/* */
/* 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 */
/* */
/* */
/* This file contains structures and definitions for the SCSI RDMA Protocol */
/* (SRP) as defined in the T10 standard available at www.t10.org. This */
/* file was based on the 16a version of the standard */
/* */
/*****************************************************************************/
#ifndef SRP_H
#define SRP_H
#define SRP_VERSION "16.a"
#define PACKED __attribute__((packed))
enum srp_types {
SRP_LOGIN_REQ_TYPE = 0x00,
SRP_LOGIN_RSP_TYPE = 0xC0,
SRP_LOGIN_REJ_TYPE = 0xC2,
SRP_I_LOGOUT_TYPE = 0x03,
SRP_T_LOGOUT_TYPE = 0x80,
SRP_TSK_MGMT_TYPE = 0x01,
SRP_CMD_TYPE = 0x02,
SRP_RSP_TYPE = 0xC1,
SRP_CRED_REQ_TYPE = 0x81,
SRP_CRED_RSP_TYPE = 0x41,
SRP_AER_REQ_TYPE = 0x82,
SRP_AER_RSP_TYPE = 0x42
};
enum srp_descriptor_formats {
SRP_NO_BUFFER = 0x00,
SRP_DIRECT_BUFFER = 0x01,
SRP_INDIRECT_BUFFER = 0x02
};
struct memory_descriptor {
u64 virtual_address;
u32 memory_handle;
u32 length;
};
struct indirect_descriptor {
struct memory_descriptor head;
u32 total_length;
struct memory_descriptor list[1] PACKED;
};
struct srp_generic {
u8 type;
u8 reserved1[7];
u64 tag;
};
struct srp_login_req {
u8 type;
u8 reserved1[7];
u64 tag;
u32 max_requested_initiator_to_target_iulen;
u32 reserved2;
u16 required_buffer_formats;
u8 reserved3:6;
u8 multi_channel_action:2;
u8 reserved4;
u32 reserved5;
u8 initiator_port_identifier[16];
u8 target_port_identifier[16];
};
struct srp_login_rsp {
u8 type;
u8 reserved1[3];
u32 request_limit_delta;
u64 tag;
u32 max_initiator_to_target_iulen;
u32 max_target_to_initiator_iulen;
u16 supported_buffer_formats;
u8 reserved2:6;
u8 multi_channel_result:2;
u8 reserved3;
u8 reserved4[24];
};
struct srp_login_rej {
u8 type;
u8 reserved1[3];
u32 reason;
u64 tag;
u64 reserved2;
u16 supported_buffer_formats;
u8 reserved3[6];
};
struct srp_i_logout {
u8 type;
u8 reserved1[7];
u64 tag;
};
struct srp_t_logout {
u8 type;
u8 reserved1[3];
u32 reason;
u64 tag;
};
struct srp_tsk_mgmt {
u8 type;
u8 reserved1[7];
u64 tag;
u32 reserved2;
u64 lun PACKED;
u8 reserved3;
u8 reserved4;
u8 task_mgmt_flags;
u8 reserved5;
u64 managed_task_tag;
u64 reserved6;
};
struct srp_cmd {
u8 type;
u32 reserved1 PACKED;
u8 data_out_format:4;
u8 data_in_format:4;
u8 data_out_count;
u8 data_in_count;
u64 tag;
u32 reserved2;
u64 lun PACKED;
u8 reserved3;
u8 reserved4:5;
u8 task_attribute:3;
u8 reserved5;
u8 additional_cdb_len;
u8 cdb[16];
u8 additional_data[0x100 - 0x30];
};
struct srp_rsp {
u8 type;
u8 reserved1[3];
u32 request_limit_delta;
u64 tag;
u16 reserved2;
u8 reserved3:2;
u8 diunder:1;
u8 diover:1;
u8 dounder:1;
u8 doover:1;
u8 snsvalid:1;
u8 rspvalid:1;
u8 status;
u32 data_in_residual_count;
u32 data_out_residual_count;
u32 sense_data_list_length;
u32 response_data_list_length;
u8 sense_and_response_data[18];
};
struct srp_cred_req {
u8 type;
u8 reserved1[3];
u32 request_limit_delta;
u64 tag;
};
struct srp_cred_rsp {
u8 type;
u8 reserved1[7];
u64 tag;
};
struct srp_aer_req {
u8 type;
u8 reserved1[3];
u32 request_limit_delta;
u64 tag;
u32 reserved2;
u64 lun;
u32 sense_data_list_length;
u32 reserved3;
u8 sense_data[20];
};
struct srp_aer_rsp {
u8 type;
u8 reserved1[7];
u64 tag;
};
union srp_iu {
struct srp_generic generic;
struct srp_login_req login_req;
struct srp_login_rsp login_rsp;
struct srp_login_rej login_rej;
struct srp_i_logout i_logout;
struct srp_t_logout t_logout;
struct srp_tsk_mgmt tsk_mgmt;
struct srp_cmd cmd;
struct srp_rsp rsp;
struct srp_cred_req cred_req;
struct srp_cred_rsp cred_rsp;
struct srp_aer_req aer_req;
struct srp_aer_rsp aer_rsp;
};
#endif

View File

@ -33,7 +33,22 @@
/*****************************************************************************/ /*****************************************************************************/
#ifndef VIOSRP_H #ifndef VIOSRP_H
#define VIOSRP_H #define VIOSRP_H
#include "srp.h" #include <scsi/srp.h>
#define SRP_VERSION "16.a"
#define SRP_MAX_IU_LEN 256
union srp_iu {
struct srp_login_req login_req;
struct srp_login_rsp login_rsp;
struct srp_login_rej login_rej;
struct srp_i_logout i_logout;
struct srp_t_logout t_logout;
struct srp_tsk_mgmt tsk_mgmt;
struct srp_cmd cmd;
struct srp_rsp rsp;
u8 reserved[SRP_MAX_IU_LEN];
};
enum viosrp_crq_formats { enum viosrp_crq_formats {
VIOSRP_SRP_FORMAT = 0x01, VIOSRP_SRP_FORMAT = 0x01,

View File

@ -164,29 +164,6 @@ MODULE_PARM_DESC(auto_create, "Auto-create single device RAID 0 arrays when init
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(IPR_DRIVER_VERSION); MODULE_VERSION(IPR_DRIVER_VERSION);
static const char *ipr_gpdd_dev_end_states[] = {
"Command complete",
"Terminated by host",
"Terminated by device reset",
"Terminated by bus reset",
"Unknown",
"Command not started"
};
static const char *ipr_gpdd_dev_bus_phases[] = {
"Bus free",
"Arbitration",
"Selection",
"Message out",
"Command",
"Message in",
"Data out",
"Data in",
"Status",
"Reselection",
"Unknown"
};
/* A constant array of IOASCs/URCs/Error Messages */ /* A constant array of IOASCs/URCs/Error Messages */
static const static const
struct ipr_error_table_t ipr_error_table[] = { struct ipr_error_table_t ipr_error_table[] = {
@ -869,8 +846,8 @@ static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg,
if (hostrcb->hcam.notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) { if (hostrcb->hcam.notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) {
if (res->sdev) { if (res->sdev) {
res->sdev->hostdata = NULL;
res->del_from_ml = 1; res->del_from_ml = 1;
res->cfgte.res_handle = IPR_INVALID_RES_HANDLE;
if (ioa_cfg->allow_ml_add_del) if (ioa_cfg->allow_ml_add_del)
schedule_work(&ioa_cfg->work_q); schedule_work(&ioa_cfg->work_q);
} else } else
@ -1356,7 +1333,7 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
return; return;
if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) { if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) {
ipr_res_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr, ipr_ra_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr,
"%s\n", ipr_error_table[error_index].error); "%s\n", ipr_error_table[error_index].error);
} else { } else {
dev_err(&ioa_cfg->pdev->dev, "%s\n", dev_err(&ioa_cfg->pdev->dev, "%s\n",
@ -2107,7 +2084,6 @@ restart:
did_work = 1; did_work = 1;
sdev = res->sdev; sdev = res->sdev;
if (!scsi_device_get(sdev)) { if (!scsi_device_get(sdev)) {
res->sdev = NULL;
list_move_tail(&res->queue, &ioa_cfg->free_res_q); list_move_tail(&res->queue, &ioa_cfg->free_res_q);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
scsi_remove_device(sdev); scsi_remove_device(sdev);
@ -2124,6 +2100,7 @@ restart:
bus = res->cfgte.res_addr.bus; bus = res->cfgte.res_addr.bus;
target = res->cfgte.res_addr.target; target = res->cfgte.res_addr.target;
lun = res->cfgte.res_addr.lun; lun = res->cfgte.res_addr.lun;
res->add_to_ml = 0;
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
scsi_add_device(ioa_cfg->host, bus, target, lun); scsi_add_device(ioa_cfg->host, bus, target, lun);
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@ -3214,7 +3191,7 @@ static int ipr_slave_configure(struct scsi_device *sdev)
sdev->timeout = IPR_VSET_RW_TIMEOUT; sdev->timeout = IPR_VSET_RW_TIMEOUT;
blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS); blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
} }
if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data)) if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
sdev->allow_restart = 1; sdev->allow_restart = 1;
scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
} }
@ -3303,6 +3280,44 @@ static int ipr_eh_host_reset(struct scsi_cmnd * cmd)
return rc; return rc;
} }
/**
* ipr_device_reset - Reset the device
* @ioa_cfg: ioa config struct
* @res: resource entry struct
*
* This function issues a device reset to the affected device.
* If the device is a SCSI device, a LUN reset will be sent
* to the device first. If that does not work, a target reset
* will be sent.
*
* Return value:
* 0 on success / non-zero on failure
**/
static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_resource_entry *res)
{
struct ipr_cmnd *ipr_cmd;
struct ipr_ioarcb *ioarcb;
struct ipr_cmd_pkt *cmd_pkt;
u32 ioasc;
ENTER;
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
ioarcb = &ipr_cmd->ioarcb;
cmd_pkt = &ioarcb->cmd_pkt;
ioarcb->res_handle = res->cfgte.res_handle;
cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
LEAVE;
return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0);
}
/** /**
* ipr_eh_dev_reset - Reset the device * ipr_eh_dev_reset - Reset the device
* @scsi_cmd: scsi command struct * @scsi_cmd: scsi command struct
@ -3319,8 +3334,7 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
struct ipr_cmnd *ipr_cmd; struct ipr_cmnd *ipr_cmd;
struct ipr_ioa_cfg *ioa_cfg; struct ipr_ioa_cfg *ioa_cfg;
struct ipr_resource_entry *res; struct ipr_resource_entry *res;
struct ipr_cmd_pkt *cmd_pkt; int rc;
u32 ioasc;
ENTER; ENTER;
ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
@ -3347,25 +3361,12 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
} }
res->resetting_device = 1; res->resetting_device = 1;
scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n");
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); rc = ipr_device_reset(ioa_cfg, res);
ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle;
cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt;
cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
ipr_sdev_err(scsi_cmd->device, "Resetting device\n");
ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
res->resetting_device = 0; res->resetting_device = 0;
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
LEAVE; LEAVE;
return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS); return (rc ? FAILED : SUCCESS);
} }
static int ipr_eh_dev_reset(struct scsi_cmnd * cmd) static int ipr_eh_dev_reset(struct scsi_cmnd * cmd)
@ -3440,7 +3441,7 @@ static void ipr_abort_timeout(struct ipr_cmnd *ipr_cmd)
return; return;
} }
ipr_sdev_err(ipr_cmd->u.sdev, "Abort timed out. Resetting bus\n"); sdev_printk(KERN_ERR, ipr_cmd->u.sdev, "Abort timed out. Resetting bus.\n");
reset_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); reset_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
ipr_cmd->sibling = reset_cmd; ipr_cmd->sibling = reset_cmd;
reset_cmd->sibling = ipr_cmd; reset_cmd->sibling = ipr_cmd;
@ -3504,7 +3505,8 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd)
cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS; cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS;
ipr_cmd->u.sdev = scsi_cmd->device; ipr_cmd->u.sdev = scsi_cmd->device;
ipr_sdev_err(scsi_cmd->device, "Aborting command: %02X\n", scsi_cmd->cmnd[0]); scmd_printk(KERN_ERR, scsi_cmd, "Aborting command: %02X\n",
scsi_cmd->cmnd[0]);
ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_CANCEL_ALL_TIMEOUT); ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_CANCEL_ALL_TIMEOUT);
ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
@ -3815,7 +3817,7 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd)
if (IPR_IOASC_SENSE_KEY(ioasc) > 0) { if (IPR_IOASC_SENSE_KEY(ioasc) > 0) {
scsi_cmd->result |= (DID_ERROR << 16); scsi_cmd->result |= (DID_ERROR << 16);
ipr_sdev_err(scsi_cmd->device, scmd_printk(KERN_ERR, scsi_cmd,
"Request Sense failed with IOASC: 0x%08X\n", ioasc); "Request Sense failed with IOASC: 0x%08X\n", ioasc);
} else { } else {
memcpy(scsi_cmd->sense_buffer, ipr_cmd->sense_buffer, memcpy(scsi_cmd->sense_buffer, ipr_cmd->sense_buffer,
@ -3938,6 +3940,7 @@ static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd)
* ipr_dump_ioasa - Dump contents of IOASA * ipr_dump_ioasa - Dump contents of IOASA
* @ioa_cfg: ioa config struct * @ioa_cfg: ioa config struct
* @ipr_cmd: ipr command struct * @ipr_cmd: ipr command struct
* @res: resource entry struct
* *
* This function is invoked by the interrupt handler when ops * This function is invoked by the interrupt handler when ops
* fail. It will log the IOASA if appropriate. Only called * fail. It will log the IOASA if appropriate. Only called
@ -3947,7 +3950,7 @@ static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd)
* none * none
**/ **/
static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg, static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_cmnd *ipr_cmd) struct ipr_cmnd *ipr_cmd, struct ipr_resource_entry *res)
{ {
int i; int i;
u16 data_len; u16 data_len;
@ -3975,16 +3978,7 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg,
return; return;
} }
ipr_sdev_err(ipr_cmd->scsi_cmd->device, "%s\n", ipr_res_err(ioa_cfg, res, "%s\n", ipr_error_table[error_index].error);
ipr_error_table[error_index].error);
if ((ioasa->u.gpdd.end_state <= ARRAY_SIZE(ipr_gpdd_dev_end_states)) &&
(ioasa->u.gpdd.bus_phase <= ARRAY_SIZE(ipr_gpdd_dev_bus_phases))) {
ipr_sdev_err(ipr_cmd->scsi_cmd->device,
"Device End state: %s Phase: %s\n",
ipr_gpdd_dev_end_states[ioasa->u.gpdd.end_state],
ipr_gpdd_dev_bus_phases[ioasa->u.gpdd.bus_phase]);
}
if (sizeof(struct ipr_ioasa) < be16_to_cpu(ioasa->ret_stat_len)) if (sizeof(struct ipr_ioasa) < be16_to_cpu(ioasa->ret_stat_len))
data_len = sizeof(struct ipr_ioasa); data_len = sizeof(struct ipr_ioasa);
@ -4141,7 +4135,7 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
} }
if (ipr_is_gscsi(res)) if (ipr_is_gscsi(res))
ipr_dump_ioasa(ioa_cfg, ipr_cmd); ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
else else
ipr_gen_sense(ipr_cmd); ipr_gen_sense(ipr_cmd);
@ -4540,7 +4534,7 @@ static int ipr_set_supported_devs(struct ipr_cmnd *ipr_cmd)
ipr_cmd->job_step = ipr_ioa_reset_done; ipr_cmd->job_step = ipr_ioa_reset_done;
list_for_each_entry_continue(res, &ioa_cfg->used_res_q, queue) { list_for_each_entry_continue(res, &ioa_cfg->used_res_q, queue) {
if (!IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data)) if (!ipr_is_scsi_disk(res))
continue; continue;
ipr_cmd->u.res = res; ipr_cmd->u.res = res;
@ -4980,7 +4974,7 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd)
list_for_each_entry_safe(res, temp, &old_res, queue) { list_for_each_entry_safe(res, temp, &old_res, queue) {
if (res->sdev) { if (res->sdev) {
res->del_from_ml = 1; res->del_from_ml = 1;
res->sdev->hostdata = NULL; res->cfgte.res_handle = IPR_INVALID_RES_HANDLE;
list_move_tail(&res->queue, &ioa_cfg->used_res_q); list_move_tail(&res->queue, &ioa_cfg->used_res_q);
} else { } else {
list_move_tail(&res->queue, &ioa_cfg->free_res_q); list_move_tail(&res->queue, &ioa_cfg->free_res_q);

View File

@ -36,8 +36,8 @@
/* /*
* Literals * Literals
*/ */
#define IPR_DRIVER_VERSION "2.1.2" #define IPR_DRIVER_VERSION "2.1.3"
#define IPR_DRIVER_DATE "(February 8, 2006)" #define IPR_DRIVER_DATE "(March 29, 2006)"
/* /*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@ -133,6 +133,7 @@
#define IPR_MAX_SCSI_RATE(width) ((320 * 10) / ((width) / 8)) #define IPR_MAX_SCSI_RATE(width) ((320 * 10) / ((width) / 8))
#define IPR_IOA_RES_HANDLE 0xffffffff #define IPR_IOA_RES_HANDLE 0xffffffff
#define IPR_INVALID_RES_HANDLE 0
#define IPR_IOA_RES_ADDR 0x00ffffff #define IPR_IOA_RES_ADDR 0x00ffffff
/* /*
@ -1191,30 +1192,17 @@ struct ipr_ucode_image_header {
*/ */
#define ipr_err(...) printk(KERN_ERR IPR_NAME ": "__VA_ARGS__) #define ipr_err(...) printk(KERN_ERR IPR_NAME ": "__VA_ARGS__)
#define ipr_info(...) printk(KERN_INFO IPR_NAME ": "__VA_ARGS__) #define ipr_info(...) printk(KERN_INFO IPR_NAME ": "__VA_ARGS__)
#define ipr_crit(...) printk(KERN_CRIT IPR_NAME ": "__VA_ARGS__)
#define ipr_warn(...) printk(KERN_WARNING IPR_NAME": "__VA_ARGS__)
#define ipr_dbg(...) IPR_DBG_CMD(printk(KERN_INFO IPR_NAME ": "__VA_ARGS__)) #define ipr_dbg(...) IPR_DBG_CMD(printk(KERN_INFO IPR_NAME ": "__VA_ARGS__))
#define ipr_sdev_printk(level, sdev, fmt, args...) \ #define ipr_ra_printk(level, ioa_cfg, ra, fmt, ...) \
sdev_printk(level, sdev, fmt, ## args) printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, (ioa_cfg)->host->host_no, \
(ra).bus, (ra).target, (ra).lun, ##__VA_ARGS__)
#define ipr_sdev_err(sdev, fmt, ...) \ #define ipr_ra_err(ioa_cfg, ra, fmt, ...) \
ipr_sdev_printk(KERN_ERR, sdev, fmt, ##__VA_ARGS__) ipr_ra_printk(KERN_ERR, ioa_cfg, ra, fmt, ##__VA_ARGS__)
#define ipr_sdev_info(sdev, fmt, ...) \
ipr_sdev_printk(KERN_INFO, sdev, fmt, ##__VA_ARGS__)
#define ipr_sdev_dbg(sdev, fmt, ...) \
IPR_DBG_CMD(ipr_sdev_printk(KERN_INFO, sdev, fmt, ##__VA_ARGS__))
#define ipr_res_printk(level, ioa_cfg, res, fmt, ...) \
printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, ioa_cfg->host->host_no, \
res.bus, res.target, res.lun, ##__VA_ARGS__)
#define ipr_res_err(ioa_cfg, res, fmt, ...) \ #define ipr_res_err(ioa_cfg, res, fmt, ...) \
ipr_res_printk(KERN_ERR, ioa_cfg, res, fmt, ##__VA_ARGS__) ipr_ra_err(ioa_cfg, (res)->cfgte.res_addr, fmt, ##__VA_ARGS__)
#define ipr_res_dbg(ioa_cfg, res, fmt, ...) \
IPR_DBG_CMD(ipr_res_printk(KERN_INFO, ioa_cfg, res, fmt, ##__VA_ARGS__))
#define ipr_phys_res_err(ioa_cfg, res, fmt, ...) \ #define ipr_phys_res_err(ioa_cfg, res, fmt, ...) \
{ \ { \
@ -1303,6 +1291,22 @@ static inline int ipr_is_gscsi(struct ipr_resource_entry *res)
return 0; return 0;
} }
/**
* ipr_is_scsi_disk - Determine if a resource is a SCSI disk
* @res: resource entry struct
*
* Return value:
* 1 if SCSI disk / 0 if not SCSI disk
**/
static inline int ipr_is_scsi_disk(struct ipr_resource_entry *res)
{
if (ipr_is_af_dasd_device(res) ||
(ipr_is_gscsi(res) && IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data)))
return 1;
else
return 0;
}
/** /**
* ipr_is_naca_model - Determine if a resource is using NACA queueing model * ipr_is_naca_model - Determine if a resource is using NACA queueing model
* @res: resource entry struct * @res: resource entry struct

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -565,7 +565,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
/* /*
* If SCSI-2 or lower, store the LUN value in cmnd. * If SCSI-2 or lower, store the LUN value in cmnd.
*/ */
if (cmd->device->scsi_level <= SCSI_2) { if (cmd->device->scsi_level <= SCSI_2 &&
cmd->device->scsi_level != SCSI_UNKNOWN) {
cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) | cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
(cmd->device->lun << 5 & 0xe0); (cmd->device->lun << 5 & 0xe0);
} }
@ -1243,7 +1244,7 @@ static int __init init_scsi(void)
if (error) if (error)
goto cleanup_sysctl; goto cleanup_sysctl;
for_each_cpu(i) for_each_possible_cpu(i)
INIT_LIST_HEAD(&per_cpu(scsi_done_q, i)); INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
printk(KERN_NOTICE "SCSI subsystem initialized\n"); printk(KERN_NOTICE "SCSI subsystem initialized\n");

View File

@ -132,7 +132,9 @@ static struct {
{"CMD", "CRA-7280", NULL, BLIST_SPARSELUN}, /* CMD RAID Controller */ {"CMD", "CRA-7280", NULL, BLIST_SPARSELUN}, /* CMD RAID Controller */
{"CNSI", "G7324", NULL, BLIST_SPARSELUN}, /* Chaparral G7324 RAID */ {"CNSI", "G7324", NULL, BLIST_SPARSELUN}, /* Chaparral G7324 RAID */
{"CNSi", "G8324", NULL, BLIST_SPARSELUN}, /* Chaparral G8324 RAID */ {"CNSi", "G8324", NULL, BLIST_SPARSELUN}, /* Chaparral G8324 RAID */
{"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN}, {"COMPAQ", "ARRAY CONTROLLER", NULL, BLIST_SPARSELUN | BLIST_LARGELUN |
BLIST_MAX_512 | BLIST_REPORTLUN2}, /* Compaq RA4x00 */
{"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN | BLIST_MAX_512}, /* Compaq RA4x00 */
{"COMPAQ", "CR3500", NULL, BLIST_FORCELUN}, {"COMPAQ", "CR3500", NULL, BLIST_FORCELUN},
{"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
{"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},

View File

@ -157,180 +157,6 @@ int scsi_set_medium_removal(struct scsi_device *sdev, char state)
} }
EXPORT_SYMBOL(scsi_set_medium_removal); EXPORT_SYMBOL(scsi_set_medium_removal);
/*
* This interface is deprecated - users should use the scsi generic (sg)
* interface instead, as this is a more flexible approach to performing
* generic SCSI commands on a device.
*
* The structure that we are passed should look like:
*
* struct sdata {
* unsigned int inlen; [i] Length of data to be written to device
* unsigned int outlen; [i] Length of data to be read from device
* unsigned char cmd[x]; [i] SCSI command (6 <= x <= 12).
* [o] Data read from device starts here.
* [o] On error, sense buffer starts here.
* unsigned char wdata[y]; [i] Data written to device starts here.
* };
* Notes:
* - The SCSI command length is determined by examining the 1st byte
* of the given command. There is no way to override this.
* - Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha).
* - The length (x + y) must be at least OMAX_SB_LEN bytes long to
* accommodate the sense buffer when an error occurs.
* The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that
* old code will not be surprised.
* - If a Unix error occurs (e.g. ENOMEM) then the user will receive
* a negative return and the Unix error code in 'errno'.
* If the SCSI command succeeds then 0 is returned.
* Positive numbers returned are the compacted SCSI error codes (4
* bytes in one int) where the lowest byte is the SCSI status.
* See the drivers/scsi/scsi.h file for more information on this.
*
*/
#define OMAX_SB_LEN 16 /* Old sense buffer length */
int scsi_ioctl_send_command(struct scsi_device *sdev,
struct scsi_ioctl_command __user *sic)
{
char *buf;
unsigned char cmd[MAX_COMMAND_SIZE];
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
char __user *cmd_in;
unsigned char opcode;
unsigned int inlen, outlen, cmdlen;
unsigned int needed, buf_needed;
int timeout, retries, result;
int data_direction;
gfp_t gfp_mask = GFP_KERNEL;
if (!sic)
return -EINVAL;
if (sdev->host->unchecked_isa_dma)
gfp_mask |= GFP_DMA;
/*
* Verify that we can read at least this much.
*/
if (!access_ok(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command)))
return -EFAULT;
if(__get_user(inlen, &sic->inlen))
return -EFAULT;
if(__get_user(outlen, &sic->outlen))
return -EFAULT;
/*
* We do not transfer more than MAX_BUF with this interface.
* If the user needs to transfer more data than this, they
* should use scsi_generics (sg) instead.
*/
if (inlen > MAX_BUF)
return -EINVAL;
if (outlen > MAX_BUF)
return -EINVAL;
cmd_in = sic->data;
if(get_user(opcode, cmd_in))
return -EFAULT;
needed = buf_needed = (inlen > outlen ? inlen : outlen);
if (buf_needed) {
buf_needed = (buf_needed + 511) & ~511;
if (buf_needed > MAX_BUF)
buf_needed = MAX_BUF;
buf = kzalloc(buf_needed, gfp_mask);
if (!buf)
return -ENOMEM;
if (inlen == 0) {
data_direction = DMA_FROM_DEVICE;
} else if (outlen == 0 ) {
data_direction = DMA_TO_DEVICE;
} else {
/*
* Can this ever happen?
*/
data_direction = DMA_BIDIRECTIONAL;
}
} else {
buf = NULL;
data_direction = DMA_NONE;
}
/*
* Obtain the command from the user's address space.
*/
cmdlen = COMMAND_SIZE(opcode);
result = -EFAULT;
if (!access_ok(VERIFY_READ, cmd_in, cmdlen + inlen))
goto error;
if(__copy_from_user(cmd, cmd_in, cmdlen))
goto error;
/*
* Obtain the data to be sent to the device (if any).
*/
if(inlen && copy_from_user(buf, cmd_in + cmdlen, inlen))
goto error;
switch (opcode) {
case SEND_DIAGNOSTIC:
case FORMAT_UNIT:
timeout = FORMAT_UNIT_TIMEOUT;
retries = 1;
break;
case START_STOP:
timeout = START_STOP_TIMEOUT;
retries = NORMAL_RETRIES;
break;
case MOVE_MEDIUM:
timeout = MOVE_MEDIUM_TIMEOUT;
retries = NORMAL_RETRIES;
break;
case READ_ELEMENT_STATUS:
timeout = READ_ELEMENT_STATUS_TIMEOUT;
retries = NORMAL_RETRIES;
break;
case READ_DEFECT_DATA:
timeout = READ_DEFECT_DATA_TIMEOUT;
retries = 1;
break;
default:
timeout = IOCTL_NORMAL_TIMEOUT;
retries = NORMAL_RETRIES;
break;
}
result = scsi_execute(sdev, cmd, data_direction, buf, needed,
sense, timeout, retries, 0);
/*
* If there was an error condition, pass the info back to the user.
*/
if (result) {
int sb_len = sizeof(*sense);
sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len;
if (copy_to_user(cmd_in, sense, sb_len))
result = -EFAULT;
} else {
if (outlen && copy_to_user(cmd_in, buf, outlen))
result = -EFAULT;
}
error:
kfree(buf);
return result;
}
EXPORT_SYMBOL(scsi_ioctl_send_command);
/* /*
* The scsi_ioctl_get_pci() function places into arg the value * The scsi_ioctl_get_pci() function places into arg the value
* pci_dev::slot_name (8 characters) for the PCI device (if any). * pci_dev::slot_name (8 characters) for the PCI device (if any).
@ -409,7 +235,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
case SCSI_IOCTL_SEND_COMMAND: case SCSI_IOCTL_SEND_COMMAND:
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
return -EACCES; return -EACCES;
return scsi_ioctl_send_command(sdev, arg); return sg_scsi_ioctl(NULL, sdev->request_queue, NULL, arg);
case SCSI_IOCTL_DOORLOCK: case SCSI_IOCTL_DOORLOCK:
return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
case SCSI_IOCTL_DOORUNLOCK: case SCSI_IOCTL_DOORUNLOCK:

View File

@ -1479,6 +1479,8 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
static void scsi_kill_request(struct request *req, request_queue_t *q) static void scsi_kill_request(struct request *req, request_queue_t *q)
{ {
struct scsi_cmnd *cmd = req->special; struct scsi_cmnd *cmd = req->special;
struct scsi_device *sdev = cmd->device;
struct Scsi_Host *shost = sdev->host;
blkdev_dequeue_request(req); blkdev_dequeue_request(req);
@ -1491,6 +1493,19 @@ static void scsi_kill_request(struct request *req, request_queue_t *q)
scsi_init_cmd_errh(cmd); scsi_init_cmd_errh(cmd);
cmd->result = DID_NO_CONNECT << 16; cmd->result = DID_NO_CONNECT << 16;
atomic_inc(&cmd->device->iorequest_cnt); atomic_inc(&cmd->device->iorequest_cnt);
/*
* SCSI request completion path will do scsi_device_unbusy(),
* bump busy counts. To bump the counters, we need to dance
* with the locks as normal issue path does.
*/
sdev->device_busy++;
spin_unlock(sdev->request_queue->queue_lock);
spin_lock(shost->host_lock);
shost->host_busy++;
spin_unlock(shost->host_lock);
spin_lock(sdev->request_queue->queue_lock);
__scsi_done(cmd); __scsi_done(cmd);
} }

View File

@ -0,0 +1,38 @@
#ifndef _SCSI_SAS_INTERNAL_H
#define _SCSI_SAS_INTERNAL_H
#define SAS_HOST_ATTRS 0
#define SAS_PORT_ATTRS 17
#define SAS_RPORT_ATTRS 7
#define SAS_END_DEV_ATTRS 3
#define SAS_EXPANDER_ATTRS 7
struct sas_internal {
struct scsi_transport_template t;
struct sas_function_template *f;
struct sas_domain_function_template *dft;
struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS];
struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS];
struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS];
struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS];
struct transport_container phy_attr_cont;
struct transport_container rphy_attr_cont;
struct transport_container end_dev_attr_cont;
struct transport_container expander_attr_cont;
/*
* The array of null terminated pointers to attributes
* needed by scsi_sysfs.c
*/
struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1];
struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1];
struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1];
};
#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t)
#endif

View File

@ -673,6 +673,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
case TYPE_MEDIUM_CHANGER: case TYPE_MEDIUM_CHANGER:
case TYPE_ENCLOSURE: case TYPE_ENCLOSURE:
case TYPE_COMM: case TYPE_COMM:
case TYPE_RAID:
case TYPE_RBC: case TYPE_RBC:
sdev->writeable = 1; sdev->writeable = 1;
break; break;
@ -737,6 +738,13 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
if (*bflags & BLIST_SELECT_NO_ATN) if (*bflags & BLIST_SELECT_NO_ATN)
sdev->select_no_atn = 1; sdev->select_no_atn = 1;
/*
* Maximum 512 sector transfer length
* broken RA4x00 Compaq Disk Array
*/
if (*bflags & BLIST_MAX_512)
blk_queue_max_sectors(sdev->request_queue, 512);
/* /*
* Some devices may not want to have a start command automatically * Some devices may not want to have a start command automatically
* issued when a device is added. * issued when a device is added.
@ -1123,10 +1131,13 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
* Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does * Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does
* support more than 8 LUNs. * support more than 8 LUNs.
*/ */
if ((bflags & BLIST_NOREPORTLUN) || if (bflags & BLIST_NOREPORTLUN)
starget->scsi_level < SCSI_2 || return 1;
(starget->scsi_level < SCSI_3 && if (starget->scsi_level < SCSI_2 &&
(!(bflags & BLIST_REPORTLUN2) || shost->max_lun <= 8)) ) starget->scsi_level != SCSI_UNKNOWN)
return 1;
if (starget->scsi_level < SCSI_3 &&
(!(bflags & BLIST_REPORTLUN2) || shost->max_lun <= 8))
return 1; return 1;
if (bflags & BLIST_NOLUN) if (bflags & BLIST_NOLUN)
return 0; return 0;

View File

@ -34,6 +34,8 @@
#include <scsi/scsi_cmnd.h> #include <scsi/scsi_cmnd.h>
#include "scsi_priv.h" #include "scsi_priv.h"
static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
/* /*
* Redefine so that we can have same named attributes in the * Redefine so that we can have same named attributes in the
* sdev/starget/host objects. * sdev/starget/host objects.
@ -213,10 +215,8 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
#define FC_MGMTSRVR_PORTID 0x00000a #define FC_MGMTSRVR_PORTID 0x00000a
static void fc_shost_remove_rports(void *data);
static void fc_timeout_deleted_rport(void *data); static void fc_timeout_deleted_rport(void *data);
static void fc_scsi_scan_rport(void *data); static void fc_scsi_scan_rport(void *data);
static void fc_rport_terminate(struct fc_rport *rport);
/* /*
* Attribute counts pre object type... * Attribute counts pre object type...
@ -288,42 +288,58 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
struct class_device *cdev) struct class_device *cdev)
{ {
struct Scsi_Host *shost = dev_to_shost(dev); struct Scsi_Host *shost = dev_to_shost(dev);
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
/* /*
* Set default values easily detected by the midlayer as * Set default values easily detected by the midlayer as
* failure cases. The scsi lldd is responsible for initializing * failure cases. The scsi lldd is responsible for initializing
* all transport attributes to valid values per host. * all transport attributes to valid values per host.
*/ */
fc_host_node_name(shost) = -1; fc_host->node_name = -1;
fc_host_port_name(shost) = -1; fc_host->port_name = -1;
fc_host_permanent_port_name(shost) = -1; fc_host->permanent_port_name = -1;
fc_host_supported_classes(shost) = FC_COS_UNSPECIFIED; fc_host->supported_classes = FC_COS_UNSPECIFIED;
memset(fc_host_supported_fc4s(shost), 0, memset(fc_host->supported_fc4s, 0,
sizeof(fc_host_supported_fc4s(shost))); sizeof(fc_host->supported_fc4s));
memset(fc_host_symbolic_name(shost), 0, memset(fc_host->symbolic_name, 0,
sizeof(fc_host_symbolic_name(shost))); sizeof(fc_host->symbolic_name));
fc_host_supported_speeds(shost) = FC_PORTSPEED_UNKNOWN; fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN;
fc_host_maxframe_size(shost) = -1; fc_host->maxframe_size = -1;
memset(fc_host_serial_number(shost), 0, memset(fc_host->serial_number, 0,
sizeof(fc_host_serial_number(shost))); sizeof(fc_host->serial_number));
fc_host_port_id(shost) = -1; fc_host->port_id = -1;
fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; fc_host->port_type = FC_PORTTYPE_UNKNOWN;
fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; fc_host->port_state = FC_PORTSTATE_UNKNOWN;
memset(fc_host_active_fc4s(shost), 0, memset(fc_host->active_fc4s, 0,
sizeof(fc_host_active_fc4s(shost))); sizeof(fc_host->active_fc4s));
fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; fc_host->speed = FC_PORTSPEED_UNKNOWN;
fc_host_fabric_name(shost) = -1; fc_host->fabric_name = -1;
fc_host_tgtid_bind_type(shost) = FC_TGTID_BIND_BY_WWPN; fc_host->tgtid_bind_type = FC_TGTID_BIND_BY_WWPN;
INIT_LIST_HEAD(&fc_host_rports(shost)); INIT_LIST_HEAD(&fc_host->rports);
INIT_LIST_HEAD(&fc_host_rport_bindings(shost)); INIT_LIST_HEAD(&fc_host->rport_bindings);
fc_host_next_rport_number(shost) = 0; fc_host->next_rport_number = 0;
fc_host_next_target_id(shost) = 0; fc_host->next_target_id = 0;
snprintf(fc_host->work_q_name, KOBJ_NAME_LEN, "fc_wq_%d",
shost->host_no);
fc_host->work_q = create_singlethread_workqueue(
fc_host->work_q_name);
if (!fc_host->work_q)
return -ENOMEM;
snprintf(fc_host->devloss_work_q_name, KOBJ_NAME_LEN, "fc_dl_%d",
shost->host_no);
fc_host->devloss_work_q = create_singlethread_workqueue(
fc_host->devloss_work_q_name);
if (!fc_host->devloss_work_q) {
destroy_workqueue(fc_host->work_q);
fc_host->work_q = NULL;
return -ENOMEM;
}
fc_host_flags(shost) = 0;
INIT_WORK(&fc_host_rport_del_work(shost), fc_shost_remove_rports, shost);
return 0; return 0;
} }
@ -879,9 +895,9 @@ store_fc_private_host_tgtid_bind_type(struct class_device *cdev,
while (!list_empty(&fc_host_rport_bindings(shost))) { while (!list_empty(&fc_host_rport_bindings(shost))) {
get_list_head_entry(rport, get_list_head_entry(rport,
&fc_host_rport_bindings(shost), peers); &fc_host_rport_bindings(shost), peers);
spin_unlock_irqrestore(shost->host_lock, flags); list_del(&rport->peers);
fc_rport_terminate(rport); rport->port_state = FC_PORTSTATE_DELETED;
spin_lock_irqsave(shost->host_lock, flags); fc_queue_work(shost, &rport->rport_delete_work);
} }
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
} }
@ -1262,6 +1278,90 @@ void fc_release_transport(struct scsi_transport_template *t)
} }
EXPORT_SYMBOL(fc_release_transport); EXPORT_SYMBOL(fc_release_transport);
/**
* fc_queue_work - Queue work to the fc_host workqueue.
* @shost: Pointer to Scsi_Host bound to fc_host.
* @work: Work to queue for execution.
*
* Return value:
* 0 on success / != 0 for error
**/
static int
fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
{
if (unlikely(!fc_host_work_q(shost))) {
printk(KERN_ERR
"ERROR: FC host '%s' attempted to queue work, "
"when no workqueue created.\n", shost->hostt->name);
dump_stack();
return -EINVAL;
}
return queue_work(fc_host_work_q(shost), work);
}
/**
* fc_flush_work - Flush a fc_host's workqueue.
* @shost: Pointer to Scsi_Host bound to fc_host.
**/
static void
fc_flush_work(struct Scsi_Host *shost)
{
if (!fc_host_work_q(shost)) {
printk(KERN_ERR
"ERROR: FC host '%s' attempted to flush work, "
"when no workqueue created.\n", shost->hostt->name);
dump_stack();
return;
}
flush_workqueue(fc_host_work_q(shost));
}
/**
* fc_queue_devloss_work - Schedule work for the fc_host devloss workqueue.
* @shost: Pointer to Scsi_Host bound to fc_host.
* @work: Work to queue for execution.
* @delay: jiffies to delay the work queuing
*
* Return value:
* 0 on success / != 0 for error
**/
static int
fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work,
unsigned long delay)
{
if (unlikely(!fc_host_devloss_work_q(shost))) {
printk(KERN_ERR
"ERROR: FC host '%s' attempted to queue work, "
"when no workqueue created.\n", shost->hostt->name);
dump_stack();
return -EINVAL;
}
return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay);
}
/**
* fc_flush_devloss - Flush a fc_host's devloss workqueue.
* @shost: Pointer to Scsi_Host bound to fc_host.
**/
static void
fc_flush_devloss(struct Scsi_Host *shost)
{
if (!fc_host_devloss_work_q(shost)) {
printk(KERN_ERR
"ERROR: FC host '%s' attempted to flush work, "
"when no workqueue created.\n", shost->hostt->name);
dump_stack();
return;
}
flush_workqueue(fc_host_devloss_work_q(shost));
}
/** /**
* fc_remove_host - called to terminate any fc_transport-related elements * fc_remove_host - called to terminate any fc_transport-related elements
@ -1283,36 +1383,103 @@ void
fc_remove_host(struct Scsi_Host *shost) fc_remove_host(struct Scsi_Host *shost)
{ {
struct fc_rport *rport, *next_rport; struct fc_rport *rport, *next_rport;
struct workqueue_struct *work_q;
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
/* Remove any remote ports */ /* Remove any remote ports */
list_for_each_entry_safe(rport, next_rport, list_for_each_entry_safe(rport, next_rport,
&fc_host_rports(shost), peers) &fc_host->rports, peers) {
fc_rport_terminate(rport); list_del(&rport->peers);
rport->port_state = FC_PORTSTATE_DELETED;
fc_queue_work(shost, &rport->rport_delete_work);
}
list_for_each_entry_safe(rport, next_rport, list_for_each_entry_safe(rport, next_rport,
&fc_host_rport_bindings(shost), peers) &fc_host->rport_bindings, peers) {
fc_rport_terminate(rport); list_del(&rport->peers);
rport->port_state = FC_PORTSTATE_DELETED;
fc_queue_work(shost, &rport->rport_delete_work);
}
/* flush all scan work items */
scsi_flush_work(shost);
/* flush all stgt delete, and rport delete work items, then kill it */
if (fc_host->work_q) {
work_q = fc_host->work_q;
fc_host->work_q = NULL;
destroy_workqueue(work_q);
}
/* flush all devloss work items, then kill it */
if (fc_host->devloss_work_q) {
work_q = fc_host->devloss_work_q;
fc_host->devloss_work_q = NULL;
destroy_workqueue(work_q);
}
} }
EXPORT_SYMBOL(fc_remove_host); EXPORT_SYMBOL(fc_remove_host);
/*
* fc_rport_tgt_remove - Removes the scsi target on the remote port /**
* @rport: The remote port to be operated on * fc_starget_delete - called to delete the scsi decendents of an rport
*/ * (target and all sdevs)
*
* @data: remote port to be operated on.
**/
static void static void
fc_rport_tgt_remove(struct fc_rport *rport) fc_starget_delete(void *data)
{ {
struct fc_rport *rport = (struct fc_rport *)data;
struct Scsi_Host *shost = rport_to_shost(rport); struct Scsi_Host *shost = rport_to_shost(rport);
unsigned long flags;
scsi_target_unblock(&rport->dev); scsi_target_unblock(&rport->dev);
/* Stop anything on the workq */ spin_lock_irqsave(shost->host_lock, flags);
if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
spin_unlock_irqrestore(shost->host_lock, flags);
if (!cancel_delayed_work(&rport->dev_loss_work)) if (!cancel_delayed_work(&rport->dev_loss_work))
flush_scheduled_work(); fc_flush_devloss(shost);
scsi_flush_work(shost); spin_lock_irqsave(shost->host_lock, flags);
rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
}
spin_unlock_irqrestore(shost->host_lock, flags);
scsi_remove_target(&rport->dev); scsi_remove_target(&rport->dev);
} }
/**
* fc_rport_final_delete - finish rport termination and delete it.
*
* @data: remote port to be deleted.
**/
static void
fc_rport_final_delete(void *data)
{
struct fc_rport *rport = (struct fc_rport *)data;
struct device *dev = &rport->dev;
struct Scsi_Host *shost = rport_to_shost(rport);
/* Delete SCSI target and sdevs */
if (rport->scsi_target_id != -1)
fc_starget_delete(data);
/*
* if a scan is pending, flush the SCSI Host work_q so that
* that we can reclaim the rport scan work element.
*/
if (rport->flags & FC_RPORT_SCAN_PENDING)
scsi_flush_work(shost);
transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
put_device(&shost->shost_gendev);
}
/** /**
* fc_rport_create - allocates and creates a remote FC port. * fc_rport_create - allocates and creates a remote FC port.
* @shost: scsi host the remote port is connected to. * @shost: scsi host the remote port is connected to.
@ -1330,8 +1497,7 @@ struct fc_rport *
fc_rport_create(struct Scsi_Host *shost, int channel, fc_rport_create(struct Scsi_Host *shost, int channel,
struct fc_rport_identifiers *ids) struct fc_rport_identifiers *ids)
{ {
struct fc_host_attrs *fc_host = struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
(struct fc_host_attrs *)shost->shost_data;
struct fc_internal *fci = to_fc_internal(shost->transportt); struct fc_internal *fci = to_fc_internal(shost->transportt);
struct fc_rport *rport; struct fc_rport *rport;
struct device *dev; struct device *dev;
@ -1360,6 +1526,8 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport); INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport);
INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport); INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport);
INIT_WORK(&rport->stgt_delete_work, fc_starget_delete, rport);
INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete, rport);
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
@ -1368,7 +1536,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
rport->scsi_target_id = fc_host->next_target_id++; rport->scsi_target_id = fc_host->next_target_id++;
else else
rport->scsi_target_id = -1; rport->scsi_target_id = -1;
list_add_tail(&rport->peers, &fc_host_rports(shost)); list_add_tail(&rport->peers, &fc_host->rports);
get_device(&shost->shost_gendev); get_device(&shost->shost_gendev);
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
@ -1389,9 +1557,11 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
transport_add_device(dev); transport_add_device(dev);
transport_configure_device(dev); transport_configure_device(dev);
if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) {
/* initiate a scan of the target */ /* initiate a scan of the target */
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work); scsi_queue_work(shost, &rport->scan_work);
}
return rport; return rport;
@ -1451,10 +1621,14 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
struct fc_rport_identifiers *ids) struct fc_rport_identifiers *ids)
{ {
struct fc_internal *fci = to_fc_internal(shost->transportt); struct fc_internal *fci = to_fc_internal(shost->transportt);
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
struct fc_rport *rport; struct fc_rport *rport;
unsigned long flags; unsigned long flags;
int match = 0; int match = 0;
/* ensure any stgt delete functions are done */
fc_flush_work(shost);
/* /*
* Search the list of "active" rports, for an rport that has been * Search the list of "active" rports, for an rport that has been
* deleted, but we've held off the real delete while the target * deleted, but we've held off the real delete while the target
@ -1462,12 +1636,12 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
*/ */
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
list_for_each_entry(rport, &fc_host_rports(shost), peers) { list_for_each_entry(rport, &fc_host->rports, peers) {
if ((rport->port_state == FC_PORTSTATE_BLOCKED) && if ((rport->port_state == FC_PORTSTATE_BLOCKED) &&
(rport->channel == channel)) { (rport->channel == channel)) {
switch (fc_host_tgtid_bind_type(shost)) { switch (fc_host->tgtid_bind_type) {
case FC_TGTID_BIND_BY_WWPN: case FC_TGTID_BIND_BY_WWPN:
case FC_TGTID_BIND_NONE: case FC_TGTID_BIND_NONE:
if (rport->port_name == ids->port_name) if (rport->port_name == ids->port_name)
@ -1521,27 +1695,34 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
* transaction. * transaction.
*/ */
if (!cancel_delayed_work(work)) if (!cancel_delayed_work(work))
flush_scheduled_work(); fc_flush_devloss(shost);
spin_lock_irqsave(shost->host_lock, flags);
rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
/* initiate a scan of the target */ /* initiate a scan of the target */
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work); scsi_queue_work(shost, &rport->scan_work);
spin_unlock_irqrestore(shost->host_lock, flags);
return rport; return rport;
} }
} }
} }
/* Search the bindings array */ /* Search the bindings array */
if (fc_host_tgtid_bind_type(shost) != FC_TGTID_BIND_NONE) { if (fc_host->tgtid_bind_type != FC_TGTID_BIND_NONE) {
/* search for a matching consistent binding */ /* search for a matching consistent binding */
list_for_each_entry(rport, &fc_host_rport_bindings(shost), list_for_each_entry(rport, &fc_host->rport_bindings,
peers) { peers) {
if (rport->channel != channel) if (rport->channel != channel)
continue; continue;
switch (fc_host_tgtid_bind_type(shost)) { switch (fc_host->tgtid_bind_type) {
case FC_TGTID_BIND_BY_WWPN: case FC_TGTID_BIND_BY_WWPN:
if (rport->port_name == ids->port_name) if (rport->port_name == ids->port_name)
match = 1; match = 1;
@ -1559,8 +1740,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
} }
if (match) { if (match) {
list_move_tail(&rport->peers, list_move_tail(&rport->peers, &fc_host->rports);
&fc_host_rports(shost));
break; break;
} }
} }
@ -1574,15 +1754,17 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
rport->roles = ids->roles; rport->roles = ids->roles;
rport->port_state = FC_PORTSTATE_ONLINE; rport->port_state = FC_PORTSTATE_ONLINE;
spin_unlock_irqrestore(shost->host_lock, flags);
if (fci->f->dd_fcrport_size) if (fci->f->dd_fcrport_size)
memset(rport->dd_data, 0, memset(rport->dd_data, 0,
fci->f->dd_fcrport_size); fci->f->dd_fcrport_size);
if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) {
/* initiate a scan of the target */ /* initiate a scan of the target */
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work); scsi_queue_work(shost, &rport->scan_work);
}
spin_unlock_irqrestore(shost->host_lock, flags);
return rport; return rport;
} }
@ -1597,30 +1779,6 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
} }
EXPORT_SYMBOL(fc_remote_port_add); EXPORT_SYMBOL(fc_remote_port_add);
/*
* fc_rport_terminate - this routine tears down and deallocates a remote port.
* @rport: The remote port to be terminated
*
* Notes:
* This routine assumes no locks are held on entry.
*/
static void
fc_rport_terminate(struct fc_rport *rport)
{
struct Scsi_Host *shost = rport_to_shost(rport);
struct device *dev = &rport->dev;
unsigned long flags;
fc_rport_tgt_remove(rport);
transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
spin_lock_irqsave(shost->host_lock, flags);
list_del(&rport->peers);
spin_unlock_irqrestore(shost->host_lock, flags);
put_device(&shost->shost_gendev);
}
/** /**
* fc_remote_port_delete - notifies the fc transport that a remote * fc_remote_port_delete - notifies the fc transport that a remote
@ -1675,20 +1833,39 @@ fc_rport_terminate(struct fc_rport *rport)
void void
fc_remote_port_delete(struct fc_rport *rport) fc_remote_port_delete(struct fc_rport *rport)
{ {
struct Scsi_Host *shost = rport_to_shost(rport);
int timeout = rport->dev_loss_tmo; int timeout = rport->dev_loss_tmo;
unsigned long flags;
/*
* No need to flush the fc_host work_q's, as all adds are synchronous.
*
* We do need to reclaim the rport scan work element, so eventually
* (in fc_rport_final_delete()) we'll flush the scsi host work_q if
* there's still a scan pending.
*/
spin_lock_irqsave(shost->host_lock, flags);
/* If no scsi target id mapping, delete it */ /* If no scsi target id mapping, delete it */
if (rport->scsi_target_id == -1) { if (rport->scsi_target_id == -1) {
fc_rport_terminate(rport); list_del(&rport->peers);
rport->port_state = FC_PORTSTATE_DELETED;
fc_queue_work(shost, &rport->rport_delete_work);
spin_unlock_irqrestore(shost->host_lock, flags);
return; return;
} }
rport->port_state = FC_PORTSTATE_BLOCKED;
rport->flags |= FC_RPORT_DEVLOSS_PENDING;
spin_unlock_irqrestore(shost->host_lock, flags);
scsi_target_block(&rport->dev); scsi_target_block(&rport->dev);
/* cap the length the devices can be blocked until they are deleted */ /* cap the length the devices can be blocked until they are deleted */
schedule_delayed_work(&rport->dev_loss_work, timeout * HZ); fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ);
rport->port_state = FC_PORTSTATE_BLOCKED;
} }
EXPORT_SYMBOL(fc_remote_port_delete); EXPORT_SYMBOL(fc_remote_port_delete);
@ -1716,8 +1893,7 @@ void
fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
{ {
struct Scsi_Host *shost = rport_to_shost(rport); struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_host_attrs *fc_host = struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
(struct fc_host_attrs *)shost->shost_data;
unsigned long flags; unsigned long flags;
int create = 0; int create = 0;
@ -1729,10 +1905,11 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
} else if (!(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) } else if (!(rport->roles & FC_RPORT_ROLE_FCP_TARGET))
create = 1; create = 1;
} }
spin_unlock_irqrestore(shost->host_lock, flags);
rport->roles = roles; rport->roles = roles;
spin_unlock_irqrestore(shost->host_lock, flags);
if (create) { if (create) {
/* /*
* There may have been a delete timer running on the * There may have been a delete timer running on the
@ -1747,10 +1924,20 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
* transaction. * transaction.
*/ */
if (!cancel_delayed_work(&rport->dev_loss_work)) if (!cancel_delayed_work(&rport->dev_loss_work))
flush_scheduled_work(); fc_flush_devloss(shost);
spin_lock_irqsave(shost->host_lock, flags);
rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
spin_unlock_irqrestore(shost->host_lock, flags);
/* ensure any stgt delete functions are done */
fc_flush_work(shost);
/* initiate a scan of the target */ /* initiate a scan of the target */
spin_lock_irqsave(shost->host_lock, flags);
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work); scsi_queue_work(shost, &rport->scan_work);
spin_unlock_irqrestore(shost->host_lock, flags);
} }
} }
EXPORT_SYMBOL(fc_remote_port_rolechg); EXPORT_SYMBOL(fc_remote_port_rolechg);
@ -1767,22 +1954,24 @@ fc_timeout_deleted_rport(void *data)
{ {
struct fc_rport *rport = (struct fc_rport *)data; struct fc_rport *rport = (struct fc_rport *)data;
struct Scsi_Host *shost = rport_to_shost(rport); struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
/* /*
* If the port is ONLINE, then it came back, but was no longer an * If the port is ONLINE, then it came back. Validate it's still an
* FCP target. Thus we need to tear down the scsi_target on it. * FCP target. If not, tear down the scsi_target on it.
*/ */
if (rport->port_state == FC_PORTSTATE_ONLINE) { if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
spin_unlock_irqrestore(shost->host_lock, flags); !(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
dev_printk(KERN_ERR, &rport->dev, dev_printk(KERN_ERR, &rport->dev,
"blocked FC remote port time out: removing target\n"); "blocked FC remote port time out: no longer"
" a FCP target, removing starget\n");
fc_rport_tgt_remove(rport); fc_queue_work(shost, &rport->stgt_delete_work);
spin_unlock_irqrestore(shost->host_lock, flags);
return; return;
} }
@ -1793,11 +1982,13 @@ fc_timeout_deleted_rport(void *data)
return; return;
} }
if (fc_host_tgtid_bind_type(shost) == FC_TGTID_BIND_NONE) { if (fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) {
spin_unlock_irqrestore(shost->host_lock, flags); list_del(&rport->peers);
rport->port_state = FC_PORTSTATE_DELETED;
dev_printk(KERN_ERR, &rport->dev, dev_printk(KERN_ERR, &rport->dev,
"blocked FC remote port time out: removing target\n"); "blocked FC remote port time out: removing target\n");
fc_rport_terminate(rport); fc_queue_work(shost, &rport->rport_delete_work);
spin_unlock_irqrestore(shost->host_lock, flags);
return; return;
} }
@ -1805,7 +1996,7 @@ fc_timeout_deleted_rport(void *data)
"blocked FC remote port time out: removing target and " "blocked FC remote port time out: removing target and "
"saving binding\n"); "saving binding\n");
list_move_tail(&rport->peers, &fc_host_rport_bindings(shost)); list_move_tail(&rport->peers, &fc_host->rport_bindings);
/* /*
* Note: We do not remove or clear the hostdata area. This allows * Note: We do not remove or clear the hostdata area. This allows
@ -1819,10 +2010,10 @@ fc_timeout_deleted_rport(void *data)
rport->maxframe_size = -1; rport->maxframe_size = -1;
rport->supported_classes = FC_COS_UNSPECIFIED; rport->supported_classes = FC_COS_UNSPECIFIED;
rport->roles = FC_RPORT_ROLE_UNKNOWN; rport->roles = FC_RPORT_ROLE_UNKNOWN;
rport->port_state = FC_PORTSTATE_DELETED; rport->port_state = FC_PORTSTATE_NOTPRESENT;
/* remove the identifiers that aren't used in the consisting binding */ /* remove the identifiers that aren't used in the consisting binding */
switch (fc_host_tgtid_bind_type(shost)) { switch (fc_host->tgtid_bind_type) {
case FC_TGTID_BIND_BY_WWPN: case FC_TGTID_BIND_BY_WWPN:
rport->node_name = -1; rport->node_name = -1;
rport->port_id = -1; rport->port_id = -1;
@ -1843,17 +2034,8 @@ fc_timeout_deleted_rport(void *data)
* As this only occurs if the remote port (scsi target) * As this only occurs if the remote port (scsi target)
* went away and didn't come back - we'll remove * went away and didn't come back - we'll remove
* all attached scsi devices. * all attached scsi devices.
*
* We'll schedule the shost work item to perform the actual removal
* to avoid recursion in the different flush calls if we perform
* the removal in each target - and there are lots of targets
* whose timeouts fire at the same time.
*/ */
fc_queue_work(shost, &rport->stgt_delete_work);
if ( !(fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED)) {
fc_host_flags(shost) |= FC_SHOST_RPORT_DEL_SCHEDULED;
scsi_queue_work(shost, &fc_host_rport_del_work(shost));
}
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
} }
@ -1870,44 +2052,18 @@ static void
fc_scsi_scan_rport(void *data) fc_scsi_scan_rport(void *data)
{ {
struct fc_rport *rport = (struct fc_rport *)data; struct fc_rport *rport = (struct fc_rport *)data;
struct Scsi_Host *shost = rport_to_shost(rport);
scsi_target_unblock(&rport->dev);
scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id,
SCAN_WILD_CARD, 1);
}
/**
* fc_shost_remove_rports - called to remove all rports that are marked
* as in a deleted (not connected) state.
*
* @data: shost whose rports are to be looked at
**/
static void
fc_shost_remove_rports(void *data)
{
struct Scsi_Host *shost = (struct Scsi_Host *)data;
struct fc_rport *rport, *next_rport;
unsigned long flags; unsigned long flags;
if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
scsi_target_unblock(&rport->dev);
scsi_scan_target(&rport->dev, rport->channel,
rport->scsi_target_id, SCAN_WILD_CARD, 1);
}
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
while (fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED) { rport->flags &= ~FC_RPORT_SCAN_PENDING;
fc_host_flags(shost) &= ~FC_SHOST_RPORT_DEL_SCHEDULED;
restart_search:
list_for_each_entry_safe(rport, next_rport,
&fc_host_rport_bindings(shost), peers) {
if (rport->port_state == FC_PORTSTATE_DELETED) {
rport->port_state = FC_PORTSTATE_NOTPRESENT;
spin_unlock_irqrestore(shost->host_lock, flags);
fc_rport_tgt_remove(rport);
spin_lock_irqsave(shost->host_lock, flags);
goto restart_search;
}
}
}
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
} }

View File

@ -35,40 +35,7 @@
#include <scsi/scsi_transport.h> #include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_sas.h> #include <scsi/scsi_transport_sas.h>
#include "scsi_sas_internal.h"
#define SAS_HOST_ATTRS 0
#define SAS_PORT_ATTRS 17
#define SAS_RPORT_ATTRS 7
#define SAS_END_DEV_ATTRS 3
#define SAS_EXPANDER_ATTRS 7
struct sas_internal {
struct scsi_transport_template t;
struct sas_function_template *f;
struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS];
struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS];
struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS];
struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS];
struct transport_container phy_attr_cont;
struct transport_container rphy_attr_cont;
struct transport_container end_dev_attr_cont;
struct transport_container expander_attr_cont;
/*
* The array of null terminated pointers to attributes
* needed by scsi_sysfs.c
*/
struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1];
struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1];
struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1];
};
#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t)
struct sas_host_attrs { struct sas_host_attrs {
struct list_head rphy_list; struct list_head rphy_list;
struct mutex lock; struct mutex lock;
@ -406,8 +373,6 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
if (!phy) if (!phy)
return NULL; return NULL;
get_device(parent);
phy->number = number; phy->number = number;
device_initialize(&phy->dev); device_initialize(&phy->dev);
@ -459,10 +424,7 @@ EXPORT_SYMBOL(sas_phy_add);
void sas_phy_free(struct sas_phy *phy) void sas_phy_free(struct sas_phy *phy)
{ {
transport_destroy_device(&phy->dev); transport_destroy_device(&phy->dev);
put_device(phy->dev.parent); put_device(&phy->dev);
put_device(phy->dev.parent);
put_device(phy->dev.parent);
kfree(phy);
} }
EXPORT_SYMBOL(sas_phy_free); EXPORT_SYMBOL(sas_phy_free);
@ -484,7 +446,7 @@ sas_phy_delete(struct sas_phy *phy)
transport_remove_device(dev); transport_remove_device(dev);
device_del(dev); device_del(dev);
transport_destroy_device(dev); transport_destroy_device(dev);
put_device(dev->parent); put_device(dev);
} }
EXPORT_SYMBOL(sas_phy_delete); EXPORT_SYMBOL(sas_phy_delete);
@ -800,7 +762,6 @@ struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent)
rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
if (!rdev) { if (!rdev) {
put_device(&parent->dev);
return NULL; return NULL;
} }
@ -836,7 +797,6 @@ struct sas_rphy *sas_expander_alloc(struct sas_phy *parent,
rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
if (!rdev) { if (!rdev) {
put_device(&parent->dev);
return NULL; return NULL;
} }
@ -885,6 +845,8 @@ int sas_rphy_add(struct sas_rphy *rphy)
(identify->target_port_protocols & (identify->target_port_protocols &
(SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
rphy->scsi_target_id = sas_host->next_target_id++; rphy->scsi_target_id = sas_host->next_target_id++;
else if (identify->device_type == SAS_END_DEVICE)
rphy->scsi_target_id = -1;
mutex_unlock(&sas_host->lock); mutex_unlock(&sas_host->lock);
if (identify->device_type == SAS_END_DEVICE && if (identify->device_type == SAS_END_DEVICE &&
@ -910,6 +872,7 @@ EXPORT_SYMBOL(sas_rphy_add);
*/ */
void sas_rphy_free(struct sas_rphy *rphy) void sas_rphy_free(struct sas_rphy *rphy)
{ {
struct device *dev = &rphy->dev;
struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
@ -917,21 +880,9 @@ void sas_rphy_free(struct sas_rphy *rphy)
list_del(&rphy->list); list_del(&rphy->list);
mutex_unlock(&sas_host->lock); mutex_unlock(&sas_host->lock);
transport_destroy_device(&rphy->dev); transport_destroy_device(dev);
put_device(rphy->dev.parent);
put_device(rphy->dev.parent);
put_device(rphy->dev.parent);
if (rphy->identify.device_type == SAS_END_DEVICE) {
struct sas_end_device *edev = rphy_to_end_device(rphy);
kfree(edev); put_device(dev);
} else {
/* must be expander */
struct sas_expander_device *edev =
rphy_to_expander_device(rphy);
kfree(edev);
}
} }
EXPORT_SYMBOL(sas_rphy_free); EXPORT_SYMBOL(sas_rphy_free);
@ -971,7 +922,7 @@ sas_rphy_delete(struct sas_rphy *rphy)
parent->rphy = NULL; parent->rphy = NULL;
put_device(&parent->dev); put_device(dev);
} }
EXPORT_SYMBOL(sas_rphy_delete); EXPORT_SYMBOL(sas_rphy_delete);

View File

@ -748,6 +748,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
/* /*
* most likely out of mem, but could also be a bad map * most likely out of mem, but could also be a bad map
*/ */
sg_finish_rem_req(srp);
return -ENOMEM; return -ENOMEM;
} else } else
return 0; return 0;
@ -1044,7 +1045,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
if (!sg_allow_access(opcode, sdp->device->type)) if (!sg_allow_access(opcode, sdp->device->type))
return -EPERM; return -EPERM;
} }
return scsi_ioctl_send_command(sdp->device, p); return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p);
case SG_SET_DEBUG: case SG_SET_DEBUG:
result = get_user(val, ip); result = get_user(val, ip);
if (result) if (result)
@ -1798,8 +1799,10 @@ sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
res = st_map_user_pages(schp->buffer, mx_sc_elems, res = st_map_user_pages(schp->buffer, mx_sc_elems,
(unsigned long)hp->dxferp, dxfer_len, (unsigned long)hp->dxferp, dxfer_len,
(SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0); (SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0);
if (res <= 0) if (res <= 0) {
sg_remove_scat(schp);
return 1; return 1;
}
schp->k_use_sg = res; schp->k_use_sg = res;
schp->dio_in_use = 1; schp->dio_in_use = 1;
hp->info |= SG_INFO_DIRECT_IO; hp->info |= SG_INFO_DIRECT_IO;

View File

@ -40,7 +40,7 @@
#ifndef SYM_DEFS_H #ifndef SYM_DEFS_H
#define SYM_DEFS_H #define SYM_DEFS_H
#define SYM_VERSION "2.2.2" #define SYM_VERSION "2.2.3"
#define SYM_DRIVER_NAME "sym-" SYM_VERSION #define SYM_DRIVER_NAME "sym-" SYM_VERSION
/* /*

View File

@ -134,66 +134,17 @@ static void sym2_setup_params(void)
} }
} }
/*
* We used to try to deal with 64-bit BARs here, but don't any more.
* There are many parts of this driver which would need to be modified
* to handle a 64-bit base address, including scripts. I'm uncomfortable
* with making those changes when I have no way of testing it, so I'm
* just going to disable it.
*
* Note that some machines (eg HP rx8620 and Superdome) have bus addresses
* below 4GB and physical addresses above 4GB. These will continue to work.
*/
static int __devinit
pci_get_base_address(struct pci_dev *pdev, int index, unsigned long *basep)
{
u32 tmp;
unsigned long base;
#define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2))
pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp);
base = tmp;
if ((tmp & 0x7) == PCI_BASE_ADDRESS_MEM_TYPE_64) {
pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp);
if (tmp > 0) {
dev_err(&pdev->dev,
"BAR %d is 64-bit, disabling\n", index - 1);
base = 0;
}
}
if ((base & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
base &= PCI_BASE_ADDRESS_IO_MASK;
} else {
base &= PCI_BASE_ADDRESS_MEM_MASK;
}
*basep = base;
return index;
#undef PCI_BAR_OFFSET
}
static struct scsi_transport_template *sym2_transport_template = NULL; static struct scsi_transport_template *sym2_transport_template = NULL;
/*
* Used by the eh thread to wait for command completion.
* It is allocated on the eh thread stack.
*/
struct sym_eh_wait {
struct completion done;
struct timer_list timer;
void (*old_done)(struct scsi_cmnd *);
int to_do;
int timed_out;
};
/* /*
* Driver private area in the SCSI command structure. * Driver private area in the SCSI command structure.
*/ */
struct sym_ucmd { /* Override the SCSI pointer structure */ struct sym_ucmd { /* Override the SCSI pointer structure */
dma_addr_t data_mapping; dma_addr_t data_mapping;
u_char data_mapped; unsigned char data_mapped;
struct sym_eh_wait *eh_wait; unsigned char to_do; /* For error handling */
void (*old_done)(struct scsi_cmnd *); /* For error handling */
struct completion *eh_done; /* For error handling */
}; };
#define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp)) #define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp))
@ -514,8 +465,6 @@ static inline int sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *cmd, struc
*/ */
int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
{ {
struct sym_tcb *tp = &np->target[cp->target];
struct sym_lcb *lp = sym_lp(tp, cp->lun);
u32 lastp, goalp; u32 lastp, goalp;
int dir; int dir;
@ -596,7 +545,7 @@ int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct s
/* /*
* activate this job. * activate this job.
*/ */
sym_start_next_ccbs(np, lp, 2); sym_put_start_queue(np, cp);
return 0; return 0;
out_abort: out_abort:
@ -751,43 +700,21 @@ static void sym53c8xx_timer(unsigned long npref)
* What we will do regarding the involved SCSI command. * What we will do regarding the involved SCSI command.
*/ */
#define SYM_EH_DO_IGNORE 0 #define SYM_EH_DO_IGNORE 0
#define SYM_EH_DO_COMPLETE 1
#define SYM_EH_DO_WAIT 2 #define SYM_EH_DO_WAIT 2
/*
* Our general completion handler.
*/
static void __sym_eh_done(struct scsi_cmnd *cmd, int timed_out)
{
struct sym_eh_wait *ep = SYM_UCMD_PTR(cmd)->eh_wait;
if (!ep)
return;
/* Try to avoid a race here (not 100% safe) */
if (!timed_out) {
ep->timed_out = 0;
if (ep->to_do == SYM_EH_DO_WAIT && !del_timer(&ep->timer))
return;
}
/* Revert everything */
SYM_UCMD_PTR(cmd)->eh_wait = NULL;
cmd->scsi_done = ep->old_done;
/* Wake up the eh thread if it wants to sleep */
if (ep->to_do == SYM_EH_DO_WAIT)
complete(&ep->done);
}
/* /*
* scsi_done() alias when error recovery is in progress. * scsi_done() alias when error recovery is in progress.
*/ */
static void sym_eh_done(struct scsi_cmnd *cmd) { __sym_eh_done(cmd, 0); } static void sym_eh_done(struct scsi_cmnd *cmd)
{
struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd));
/* cmd->scsi_done = ucmd->old_done;
* Some timeout handler to avoid waiting too long.
*/ if (ucmd->to_do == SYM_EH_DO_WAIT)
static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1); } complete(ucmd->eh_done);
}
/* /*
* Generic method for our eh processing. * Generic method for our eh processing.
@ -796,35 +723,31 @@ static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1);
static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
{ {
struct sym_hcb *np = SYM_SOFTC_PTR(cmd); struct sym_hcb *np = SYM_SOFTC_PTR(cmd);
struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
struct Scsi_Host *host = cmd->device->host;
SYM_QUEHEAD *qp; SYM_QUEHEAD *qp;
int to_do = SYM_EH_DO_IGNORE; int to_do = SYM_EH_DO_IGNORE;
int sts = -1; int sts = -1;
struct sym_eh_wait eh, *ep = &eh; struct completion eh_done;
dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname); dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname);
spin_lock_irq(host->host_lock);
/* This one is queued in some place -> to wait for completion */ /* This one is queued in some place -> to wait for completion */
FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
if (cp->cmd == cmd) { if (cp->cmd == cmd) {
to_do = SYM_EH_DO_WAIT; to_do = SYM_EH_DO_WAIT;
goto prepare; break;
} }
} }
prepare: if (to_do == SYM_EH_DO_WAIT) {
/* Prepare stuff to either ignore, complete or wait for completion */ init_completion(&eh_done);
switch(to_do) { ucmd->old_done = cmd->scsi_done;
default: ucmd->eh_done = &eh_done;
case SYM_EH_DO_IGNORE: wmb();
break;
case SYM_EH_DO_WAIT:
init_completion(&ep->done);
/* fall through */
case SYM_EH_DO_COMPLETE:
ep->old_done = cmd->scsi_done;
cmd->scsi_done = sym_eh_done; cmd->scsi_done = sym_eh_done;
SYM_UCMD_PTR(cmd)->eh_wait = ep;
} }
/* Try to proceed the operation we have been asked for */ /* Try to proceed the operation we have been asked for */
@ -851,30 +774,20 @@ prepare:
/* On error, restore everything and cross fingers :) */ /* On error, restore everything and cross fingers :) */
if (sts) { if (sts) {
SYM_UCMD_PTR(cmd)->eh_wait = NULL; cmd->scsi_done = ucmd->old_done;
cmd->scsi_done = ep->old_done;
to_do = SYM_EH_DO_IGNORE; to_do = SYM_EH_DO_IGNORE;
} }
ep->to_do = to_do; ucmd->to_do = to_do;
/* Complete the command with locks held as required by the driver */ spin_unlock_irq(host->host_lock);
if (to_do == SYM_EH_DO_COMPLETE)
sym_xpt_done2(np, cmd, DID_ABORT);
/* Wait for completion with locks released, as required by kernel */
if (to_do == SYM_EH_DO_WAIT) { if (to_do == SYM_EH_DO_WAIT) {
init_timer(&ep->timer); if (!wait_for_completion_timeout(&eh_done, 5*HZ)) {
ep->timer.expires = jiffies + (5*HZ); ucmd->to_do = SYM_EH_DO_IGNORE;
ep->timer.function = sym_eh_timeout; wmb();
ep->timer.data = (u_long)cmd;
ep->timed_out = 1; /* Be pessimistic for once :) */
add_timer(&ep->timer);
spin_unlock_irq(np->s.host->host_lock);
wait_for_completion(&ep->done);
spin_lock_irq(np->s.host->host_lock);
if (ep->timed_out)
sts = -2; sts = -2;
} }
}
dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname, dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname,
sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed"); sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed");
return sts ? SCSI_FAILED : SCSI_SUCCESS; return sts ? SCSI_FAILED : SCSI_SUCCESS;
@ -886,46 +799,22 @@ prepare:
*/ */
static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd) static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd)
{ {
int rc; return sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd);
spin_lock_irq(cmd->device->host->host_lock);
rc = sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd);
spin_unlock_irq(cmd->device->host->host_lock);
return rc;
} }
static int sym53c8xx_eh_device_reset_handler(struct scsi_cmnd *cmd) static int sym53c8xx_eh_device_reset_handler(struct scsi_cmnd *cmd)
{ {
int rc; return sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd);
spin_lock_irq(cmd->device->host->host_lock);
rc = sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd);
spin_unlock_irq(cmd->device->host->host_lock);
return rc;
} }
static int sym53c8xx_eh_bus_reset_handler(struct scsi_cmnd *cmd) static int sym53c8xx_eh_bus_reset_handler(struct scsi_cmnd *cmd)
{ {
int rc; return sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd);
spin_lock_irq(cmd->device->host->host_lock);
rc = sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd);
spin_unlock_irq(cmd->device->host->host_lock);
return rc;
} }
static int sym53c8xx_eh_host_reset_handler(struct scsi_cmnd *cmd) static int sym53c8xx_eh_host_reset_handler(struct scsi_cmnd *cmd)
{ {
int rc; return sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd);
spin_lock_irq(cmd->device->host->host_lock);
rc = sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd);
spin_unlock_irq(cmd->device->host->host_lock);
return rc;
} }
/* /*
@ -944,15 +833,12 @@ static void sym_tune_dev_queuing(struct sym_tcb *tp, int lun, u_short reqtags)
if (reqtags > lp->s.scdev_depth) if (reqtags > lp->s.scdev_depth)
reqtags = lp->s.scdev_depth; reqtags = lp->s.scdev_depth;
lp->started_limit = reqtags ? reqtags : 2;
lp->started_max = 1;
lp->s.reqtags = reqtags; lp->s.reqtags = reqtags;
if (reqtags != oldtags) { if (reqtags != oldtags) {
dev_info(&tp->starget->dev, dev_info(&tp->starget->dev,
"tagged command queuing %s, command queue depth %d.\n", "tagged command queuing %s, command queue depth %d.\n",
lp->s.reqtags ? "enabled" : "disabled", lp->s.reqtags ? "enabled" : "disabled", reqtags);
lp->started_limit);
} }
} }
@ -1866,15 +1752,25 @@ static int __devinit sym_set_workarounds(struct sym_device *device)
static void __devinit static void __devinit
sym_init_device(struct pci_dev *pdev, struct sym_device *device) sym_init_device(struct pci_dev *pdev, struct sym_device *device)
{ {
int i; int i = 2;
struct pci_bus_region bus_addr;
device->host_id = SYM_SETUP_HOST_ID; device->host_id = SYM_SETUP_HOST_ID;
device->pdev = pdev; device->pdev = pdev;
i = pci_get_base_address(pdev, 1, &device->mmio_base); pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[1]);
pci_get_base_address(pdev, i, &device->ram_base); device->mmio_base = bus_addr.start;
#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED /*
* If the BAR is 64-bit, resource 2 will be occupied by the
* upper 32 bits
*/
if (!pdev->resource[i].flags)
i++;
pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]);
device->ram_base = bus_addr.start;
#ifdef CONFIG_SCSI_SYM53C8XX_MMIO
if (device->mmio_base) if (device->mmio_base)
device->s.ioaddr = pci_iomap(pdev, 1, device->s.ioaddr = pci_iomap(pdev, 1,
pci_resource_len(pdev, 1)); pci_resource_len(pdev, 1));
@ -1978,7 +1874,8 @@ static struct scsi_host_template sym2_template = {
.eh_bus_reset_handler = sym53c8xx_eh_bus_reset_handler, .eh_bus_reset_handler = sym53c8xx_eh_bus_reset_handler,
.eh_host_reset_handler = sym53c8xx_eh_host_reset_handler, .eh_host_reset_handler = sym53c8xx_eh_host_reset_handler,
.this_id = 7, .this_id = 7,
.use_clustering = DISABLE_CLUSTERING, .use_clustering = ENABLE_CLUSTERING,
.max_sectors = 0xFFFF,
#ifdef SYM_LINUX_PROC_INFO_SUPPORT #ifdef SYM_LINUX_PROC_INFO_SUPPORT
.proc_info = sym53c8xx_proc_info, .proc_info = sym53c8xx_proc_info,
.proc_name = NAME53C8XX, .proc_name = NAME53C8XX,

View File

@ -68,7 +68,7 @@
*/ */
#define SYM_CONF_TIMER_INTERVAL ((HZ+1)/2) #define SYM_CONF_TIMER_INTERVAL ((HZ+1)/2)
#define SYM_OPT_HANDLE_DEVICE_QUEUEING #undef SYM_OPT_HANDLE_DEVICE_QUEUEING
#define SYM_OPT_LIMIT_COMMAND_REORDERING #define SYM_OPT_LIMIT_COMMAND_REORDERING
/* /*

View File

@ -72,7 +72,10 @@ static void sym_printl_hex(u_char *p, int n)
static void sym_print_msg(struct sym_ccb *cp, char *label, u_char *msg) static void sym_print_msg(struct sym_ccb *cp, char *label, u_char *msg)
{ {
if (label)
sym_print_addr(cp->cmd, "%s: ", label); sym_print_addr(cp->cmd, "%s: ", label);
else
sym_print_addr(cp->cmd, "");
spi_print_msg(msg); spi_print_msg(msg);
printf("\n"); printf("\n");
@ -472,7 +475,7 @@ static int sym_getpciclock (struct sym_hcb *np)
* calculations more simple. * calculations more simple.
*/ */
#define _5M 5000000 #define _5M 5000000
static u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; static const u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M};
/* /*
* Get clock factor and sync divisor for a given * Get clock factor and sync divisor for a given
@ -644,6 +647,37 @@ static void sym_save_initial_setting (struct sym_hcb *np)
np->sv_ctest5 = INB(np, nc_ctest5) & 0x24; np->sv_ctest5 = INB(np, nc_ctest5) & 0x24;
} }
/*
* Set SCSI BUS mode.
* - LVD capable chips (895/895A/896/1010) report the current BUS mode
* through the STEST4 IO register.
* - For previous generation chips (825/825A/875), the user has to tell us
* how to check against HVD, since a 100% safe algorithm is not possible.
*/
static void sym_set_bus_mode(struct sym_hcb *np, struct sym_nvram *nvram)
{
if (np->scsi_mode)
return;
np->scsi_mode = SMODE_SE;
if (np->features & (FE_ULTRA2|FE_ULTRA3))
np->scsi_mode = (np->sv_stest4 & SMODE);
else if (np->features & FE_DIFF) {
if (SYM_SETUP_SCSI_DIFF == 1) {
if (np->sv_scntl3) {
if (np->sv_stest2 & 0x20)
np->scsi_mode = SMODE_HVD;
} else if (nvram->type == SYM_SYMBIOS_NVRAM) {
if (!(INB(np, nc_gpreg) & 0x08))
np->scsi_mode = SMODE_HVD;
}
} else if (SYM_SETUP_SCSI_DIFF == 2)
np->scsi_mode = SMODE_HVD;
}
if (np->scsi_mode == SMODE_HVD)
np->rv_stest2 |= 0x20;
}
/* /*
* Prepare io register values used by sym_start_up() * Prepare io register values used by sym_start_up()
* according to selected and supported features. * according to selected and supported features.
@ -654,9 +688,6 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
u32 period; u32 period;
int i; int i;
/*
* Wide ?
*/
np->maxwide = (np->features & FE_WIDE) ? 1 : 0; np->maxwide = (np->features & FE_WIDE) ? 1 : 0;
/* /*
@ -838,6 +869,7 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
* Get parity checking, host ID and verbose mode from NVRAM * Get parity checking, host ID and verbose mode from NVRAM
*/ */
np->myaddr = 255; np->myaddr = 255;
np->scsi_mode = 0;
sym_nvram_setup_host(shost, np, nvram); sym_nvram_setup_host(shost, np, nvram);
/* /*
@ -854,33 +886,7 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
*/ */
sym_init_burst(np, burst_max); sym_init_burst(np, burst_max);
/* sym_set_bus_mode(np, nvram);
* Set SCSI BUS mode.
* - LVD capable chips (895/895A/896/1010) report the
* current BUS mode through the STEST4 IO register.
* - For previous generation chips (825/825A/875),
* user has to tell us how to check against HVD,
* since a 100% safe algorithm is not possible.
*/
np->scsi_mode = SMODE_SE;
if (np->features & (FE_ULTRA2|FE_ULTRA3))
np->scsi_mode = (np->sv_stest4 & SMODE);
else if (np->features & FE_DIFF) {
if (SYM_SETUP_SCSI_DIFF == 1) {
if (np->sv_scntl3) {
if (np->sv_stest2 & 0x20)
np->scsi_mode = SMODE_HVD;
}
else if (nvram->type == SYM_SYMBIOS_NVRAM) {
if (!(INB(np, nc_gpreg) & 0x08))
np->scsi_mode = SMODE_HVD;
}
}
else if (SYM_SETUP_SCSI_DIFF == 2)
np->scsi_mode = SMODE_HVD;
}
if (np->scsi_mode == SMODE_HVD)
np->rv_stest2 |= 0x20;
/* /*
* Set LED support from SCRIPTS. * Set LED support from SCRIPTS.
@ -973,7 +979,7 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
* *
* Has to be called with interrupts disabled. * Has to be called with interrupts disabled.
*/ */
#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED #ifdef CONFIG_SCSI_SYM53C8XX_MMIO
static int sym_regtest(struct sym_hcb *np) static int sym_regtest(struct sym_hcb *np)
{ {
register volatile u32 data; register volatile u32 data;
@ -992,20 +998,25 @@ static int sym_regtest (struct sym_hcb *np)
#endif #endif
printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
(unsigned) data); (unsigned) data);
return (0x10); return 0x10;
} }
return (0); return 0;
}
#else
static inline int sym_regtest(struct sym_hcb *np)
{
return 0;
} }
#endif #endif
static int sym_snooptest(struct sym_hcb *np) static int sym_snooptest(struct sym_hcb *np)
{ {
u32 sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat; u32 sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat;
int i, err=0; int i, err;
#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED
err |= sym_regtest (np); err = sym_regtest(np);
if (err) return (err); if (err)
#endif return err;
restart_test: restart_test:
/* /*
* Enable Master Parity Checking as we intend * Enable Master Parity Checking as we intend
@ -1094,7 +1105,7 @@ restart_test:
err |= 4; err |= 4;
} }
return (err); return err;
} }
/* /*
@ -1464,7 +1475,7 @@ static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgp
/* /*
* Insert a job into the start queue. * Insert a job into the start queue.
*/ */
static void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp) void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp)
{ {
u_short qidx; u_short qidx;
@ -4481,7 +4492,7 @@ static void sym_int_sir (struct sym_hcb *np)
switch (np->msgin [2]) { switch (np->msgin [2]) {
case M_X_MODIFY_DP: case M_X_MODIFY_DP:
if (DEBUG_FLAGS & DEBUG_POINTER) if (DEBUG_FLAGS & DEBUG_POINTER)
sym_print_msg(cp,"modify DP",np->msgin); sym_print_msg(cp, NULL, np->msgin);
tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) +
(np->msgin[5]<<8) + (np->msgin[6]); (np->msgin[5]<<8) + (np->msgin[6]);
sym_modify_dp(np, tp, cp, tmp); sym_modify_dp(np, tp, cp, tmp);
@ -4508,7 +4519,7 @@ static void sym_int_sir (struct sym_hcb *np)
*/ */
case M_IGN_RESIDUE: case M_IGN_RESIDUE:
if (DEBUG_FLAGS & DEBUG_POINTER) if (DEBUG_FLAGS & DEBUG_POINTER)
sym_print_msg(cp,"ign wide residue", np->msgin); sym_print_msg(cp, NULL, np->msgin);
if (cp->host_flags & HF_SENSE) if (cp->host_flags & HF_SENSE)
OUTL_DSP(np, SCRIPTA_BA(np, clrack)); OUTL_DSP(np, SCRIPTA_BA(np, clrack));
else else
@ -4597,7 +4608,8 @@ struct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char t
* Debugging purpose. * Debugging purpose.
*/ */
#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
assert(lp->busy_itl == 0); if (lp->busy_itl != 0)
goto out_free;
#endif #endif
/* /*
* Allocate resources for tags if not yet. * Allocate resources for tags if not yet.
@ -4642,7 +4654,8 @@ struct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char t
* Debugging purpose. * Debugging purpose.
*/ */
#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
assert(lp->busy_itl == 0 && lp->busy_itlq == 0); if (lp->busy_itl != 0 || lp->busy_itlq != 0)
goto out_free;
#endif #endif
/* /*
* Count this nexus for this LUN. * Count this nexus for this LUN.

View File

@ -1049,6 +1049,8 @@ int sym_reset_scsi_bus(struct sym_hcb *np, int enab_int);
struct sym_chip *sym_lookup_chip_table(u_short device_id, u_char revision); struct sym_chip *sym_lookup_chip_table(u_short device_id, u_char revision);
#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING #ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn); void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn);
#else
void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp);
#endif #endif
void sym_start_up(struct sym_hcb *np, int reason); void sym_start_up(struct sym_hcb *np, int reason);
void sym_interrupt(struct sym_hcb *np); void sym_interrupt(struct sym_hcb *np);

View File

@ -17,6 +17,8 @@
#include <asm/scatterlist.h> #include <asm/scatterlist.h>
struct scsi_ioctl_command;
struct request_queue; struct request_queue;
typedef struct request_queue request_queue_t; typedef struct request_queue request_queue_t;
struct elevator_queue; struct elevator_queue;
@ -611,6 +613,8 @@ extern void blk_plug_device(request_queue_t *);
extern int blk_remove_plug(request_queue_t *); extern int blk_remove_plug(request_queue_t *);
extern void blk_recount_segments(request_queue_t *, struct bio *); extern void blk_recount_segments(request_queue_t *, struct bio *);
extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *); extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *);
extern int sg_scsi_ioctl(struct file *, struct request_queue *,
struct gendisk *, struct scsi_ioctl_command __user *);
extern void blk_start_queue(request_queue_t *q); extern void blk_start_queue(request_queue_t *q);
extern void blk_stop_queue(request_queue_t *q); extern void blk_stop_queue(request_queue_t *q);
extern void blk_sync_queue(struct request_queue *q); extern void blk_sync_queue(struct request_queue *q);

View File

@ -28,4 +28,5 @@
#define BLIST_NO_ULD_ATTACH 0x100000 /* device is actually for RAID config */ #define BLIST_NO_ULD_ATTACH 0x100000 /* device is actually for RAID config */
#define BLIST_SELECT_NO_ATN 0x200000 /* select without ATN */ #define BLIST_SELECT_NO_ATN 0x200000 /* select without ATN */
#define BLIST_RETRY_HWERROR 0x400000 /* retry HARDWARE_ERROR */ #define BLIST_RETRY_HWERROR 0x400000 /* retry HARDWARE_ERROR */
#define BLIST_MAX_512 0x800000 /* maximum 512 sector cdb length */
#endif #endif

View File

@ -41,8 +41,6 @@ typedef struct scsi_fctargaddress {
} Scsi_FCTargAddress; } Scsi_FCTargAddress;
extern int scsi_ioctl(struct scsi_device *, int, void __user *); extern int scsi_ioctl(struct scsi_device *, int, void __user *);
extern int scsi_ioctl_send_command(struct scsi_device *,
struct scsi_ioctl_command __user *);
extern int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, extern int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
void __user *arg, struct file *filp); void __user *arg, struct file *filp);

View File

@ -202,12 +202,19 @@ struct fc_rport { /* aka fc_starget_attrs */
/* internal data */ /* internal data */
unsigned int channel; unsigned int channel;
u32 number; u32 number;
u8 flags;
struct list_head peers; struct list_head peers;
struct device dev; struct device dev;
struct work_struct dev_loss_work; struct work_struct dev_loss_work;
struct work_struct scan_work; struct work_struct scan_work;
struct work_struct stgt_delete_work;
struct work_struct rport_delete_work;
} __attribute__((aligned(sizeof(unsigned long)))); } __attribute__((aligned(sizeof(unsigned long))));
/* bit field values for struct fc_rport "flags" field: */
#define FC_RPORT_DEVLOSS_PENDING 0x01
#define FC_RPORT_SCAN_PENDING 0x02
#define dev_to_rport(d) \ #define dev_to_rport(d) \
container_of(d, struct fc_rport, dev) container_of(d, struct fc_rport, dev)
#define transport_class_to_rport(classdev) \ #define transport_class_to_rport(classdev) \
@ -327,13 +334,16 @@ struct fc_host_attrs {
struct list_head rport_bindings; struct list_head rport_bindings;
u32 next_rport_number; u32 next_rport_number;
u32 next_target_id; u32 next_target_id;
u8 flags;
struct work_struct rport_del_work; /* work queues for rport state manipulation */
char work_q_name[KOBJ_NAME_LEN];
struct workqueue_struct *work_q;
char devloss_work_q_name[KOBJ_NAME_LEN];
struct workqueue_struct *devloss_work_q;
}; };
/* values for struct fc_host_attrs "flags" field: */ #define shost_to_fc_host(x) \
#define FC_SHOST_RPORT_DEL_SCHEDULED 0x01 ((struct fc_host_attrs *)(x)->shost_data)
#define fc_host_node_name(x) \ #define fc_host_node_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->node_name) (((struct fc_host_attrs *)(x)->shost_data)->node_name)
@ -375,10 +385,14 @@ struct fc_host_attrs {
(((struct fc_host_attrs *)(x)->shost_data)->next_rport_number) (((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
#define fc_host_next_target_id(x) \ #define fc_host_next_target_id(x) \
(((struct fc_host_attrs *)(x)->shost_data)->next_target_id) (((struct fc_host_attrs *)(x)->shost_data)->next_target_id)
#define fc_host_flags(x) \ #define fc_host_work_q_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->flags) (((struct fc_host_attrs *)(x)->shost_data)->work_q_name)
#define fc_host_rport_del_work(x) \ #define fc_host_work_q(x) \
(((struct fc_host_attrs *)(x)->shost_data)->rport_del_work) (((struct fc_host_attrs *)(x)->shost_data)->work_q)
#define fc_host_devloss_work_q_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q_name)
#define fc_host_devloss_work_q(x) \
(((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q)
/* The functions by which the transport class and the driver communicate */ /* The functions by which the transport class and the driver communicate */
@ -461,10 +475,15 @@ fc_remote_port_chkready(struct fc_rport *rport)
switch (rport->port_state) { switch (rport->port_state) {
case FC_PORTSTATE_ONLINE: case FC_PORTSTATE_ONLINE:
if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
result = 0; result = 0;
else if (rport->flags & FC_RPORT_DEVLOSS_PENDING)
result = DID_IMM_RETRY << 16;
else
result = DID_NO_CONNECT << 16;
break; break;
case FC_PORTSTATE_BLOCKED: case FC_PORTSTATE_BLOCKED:
result = DID_BUS_BUSY << 16; result = DID_IMM_RETRY << 16;
break; break;
default: default:
result = DID_NO_CONNECT << 16; result = DID_NO_CONNECT << 16;