/*
- * Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
- * Copyright 2001 Compaq Computer Corporation
+ * Disk Array driver for HP Smart Array controllers, SCSI Tape module.
+ * (C) Copyright 2001, 2007 Hewlett-Packard Development Company, L.P.
*
* 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.
+ * the Free Software Foundation; version 2 of the License.
*
* 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more details.
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 59 Temple Place, Suite 300, Boston, MA
+ * 02111-1307, USA.
*
* Questions/Comments/Bugfixes to iss_storagedev@hp.com
*
through the array controller. Note in particular, neither
physical nor logical disks are presented through the scsi layer. */
-#include <scsi/scsi.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <asm/atomic.h>
+
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
-#include <asm/atomic.h>
-#include <linux/timer.h>
-#include <linux/completion.h>
#include "cciss_scsi.h"
+#define CCISS_ABORT_MSG 0x00
+#define CCISS_RESET_MSG 0x01
+
/* some prototypes... */
static int sendcmd(
__u8 cmd,
static int cciss_scsi_queue_command (struct scsi_cmnd *cmd,
void (* done)(struct scsi_cmnd *));
+static int cciss_eh_device_reset_handler(struct scsi_cmnd *);
+static int cciss_eh_abort_handler(struct scsi_cmnd *);
static struct cciss_scsi_hba_t ccissscsi[MAX_CTLR] = {
{ .name = "cciss0", .ndevices = 0 },
.sg_tablesize = MAXSGENTRIES,
.cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
+ /* Can't have eh_bus_reset_handler or eh_host_reset_handler for cciss */
+ .eh_device_reset_handler= cciss_eh_device_reset_handler,
+ .eh_abort_handler = cciss_eh_abort_handler,
};
#pragma pack(1)
stk->pool = NULL;
}
-/* scsi_device_types comes from scsi.h */
-#define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \
- "Unknown" : scsi_device_types[n]
-
#if 0
static int xmargin=8;
static int amargin=60;
}
return (!found);
}
+struct scsi2map {
+ char scsi3addr[8];
+ int bus, target, lun;
+};
static int
cciss_scsi_add_entry(int ctlr, int hostno,
- unsigned char *scsi3addr, int devtype)
+ unsigned char *scsi3addr, int devtype,
+ struct scsi2map *added, int *nadded)
{
/* assumes hba[ctlr]->scsi_ctlr->lock is held */
int n = ccissscsi[ctlr].ndevices;
struct cciss_scsi_dev_t *sd;
+ int i, bus, target, lun;
+ unsigned char addr1[8], addr2[8];
if (n >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
printk("cciss%d: Too many devices, "
"some will be inaccessible.\n", ctlr);
return -1;
}
+
+ bus = target = -1;
+ lun = 0;
+ /* Is this device a non-zero lun of a multi-lun device */
+ /* byte 4 of the 8-byte LUN addr will contain the logical unit no. */
+ if (scsi3addr[4] != 0) {
+ /* Search through our list and find the device which */
+ /* has the same 8 byte LUN address, excepting byte 4. */
+ /* Assign the same bus and target for this new LUN. */
+ /* Use the logical unit number from the firmware. */
+ memcpy(addr1, scsi3addr, 8);
+ addr1[4] = 0;
+ for (i = 0; i < n; i++) {
+ sd = &ccissscsi[ctlr].dev[i];
+ memcpy(addr2, sd->scsi3addr, 8);
+ addr2[4] = 0;
+ /* differ only in byte 4? */
+ if (memcmp(addr1, addr2, 8) == 0) {
+ bus = sd->bus;
+ target = sd->target;
+ lun = scsi3addr[4];
+ break;
+ }
+ }
+ }
+
sd = &ccissscsi[ctlr].dev[n];
- if (find_bus_target_lun(ctlr, &sd->bus, &sd->target, &sd->lun) != 0)
- return -1;
+ if (lun == 0) {
+ if (find_bus_target_lun(ctlr,
+ &sd->bus, &sd->target, &sd->lun) != 0)
+ return -1;
+ } else {
+ sd->bus = bus;
+ sd->target = target;
+ sd->lun = lun;
+ }
+ added[*nadded].bus = sd->bus;
+ added[*nadded].target = sd->target;
+ added[*nadded].lun = sd->lun;
+ (*nadded)++;
+
memcpy(&sd->scsi3addr[0], scsi3addr, 8);
sd->devtype = devtype;
ccissscsi[ctlr].ndevices++;
time anyway (the scsi layer's inquiries will show that info) */
if (hostno != -1)
printk("cciss%d: %s device c%db%dt%dl%d added.\n",
- ctlr, DEVICETYPE(sd->devtype), hostno,
+ ctlr, scsi_device_type(sd->devtype), hostno,
sd->bus, sd->target, sd->lun);
return 0;
}
static void
-cciss_scsi_remove_entry(int ctlr, int hostno, int entry)
+cciss_scsi_remove_entry(int ctlr, int hostno, int entry,
+ struct scsi2map *removed, int *nremoved)
{
/* assumes hba[ctlr]->scsi_ctlr->lock is held */
int i;
if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return;
sd = ccissscsi[ctlr].dev[entry];
+ removed[*nremoved].bus = sd.bus;
+ removed[*nremoved].target = sd.target;
+ removed[*nremoved].lun = sd.lun;
+ (*nremoved)++;
for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++)
ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1];
ccissscsi[ctlr].ndevices--;
printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
- ctlr, DEVICETYPE(sd.devtype), hostno,
+ ctlr, scsi_device_type(sd.devtype), hostno,
sd.bus, sd.target, sd.lun);
}
(a)[1] == (b)[1] && \
(a)[0] == (b)[0])
+static void fixup_botched_add(int ctlr, char *scsi3addr)
+{
+ /* called when scsi_add_device fails in order to re-adjust */
+ /* ccissscsi[] to match the mid layer's view. */
+ unsigned long flags;
+ int i, j;
+ CPQ_TAPE_LOCK(ctlr, flags);
+ for (i = 0; i < ccissscsi[ctlr].ndevices; i++) {
+ if (memcmp(scsi3addr,
+ ccissscsi[ctlr].dev[i].scsi3addr, 8) == 0) {
+ for (j = i; j < ccissscsi[ctlr].ndevices-1; j++)
+ ccissscsi[ctlr].dev[j] =
+ ccissscsi[ctlr].dev[j+1];
+ ccissscsi[ctlr].ndevices--;
+ break;
+ }
+ }
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+}
+
static int
adjust_cciss_scsi_table(int ctlr, int hostno,
struct cciss_scsi_dev_t sd[], int nsds)
int i,j, found, changes=0;
struct cciss_scsi_dev_t *csd;
unsigned long flags;
+ struct scsi2map *added, *removed;
+ int nadded, nremoved;
+ struct Scsi_Host *sh = NULL;
+
+ added = kzalloc(sizeof(*added) * CCISS_MAX_SCSI_DEVS_PER_HBA,
+ GFP_KERNEL);
+ removed = kzalloc(sizeof(*removed) * CCISS_MAX_SCSI_DEVS_PER_HBA,
+ GFP_KERNEL);
+
+ if (!added || !removed) {
+ printk(KERN_WARNING "cciss%d: Out of memory in "
+ "adjust_cciss_scsi_table\n", ctlr);
+ goto free_and_out;
+ }
CPQ_TAPE_LOCK(ctlr, flags);
+ if (hostno != -1) /* if it's not the first time... */
+ sh = ((struct cciss_scsi_adapter_data_t *)
+ hba[ctlr]->scsi_ctlr)->scsi_host;
+
/* find any devices in ccissscsi[] that are not in
sd[] and remove them from ccissscsi[] */
i = 0;
+ nremoved = 0;
+ nadded = 0;
while(i<ccissscsi[ctlr].ndevices) {
csd = &ccissscsi[ctlr].dev[i];
found=0;
if (found == 0) { /* device no longer present. */
changes++;
/* printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
- ctlr, DEVICETYPE(csd->devtype), hostno,
+ ctlr, scsi_device_type(csd->devtype), hostno,
csd->bus, csd->target, csd->lun); */
- cciss_scsi_remove_entry(ctlr, hostno, i);
- /* note, i not incremented */
+ cciss_scsi_remove_entry(ctlr, hostno, i,
+ removed, &nremoved);
+ /* remove ^^^, hence i not incremented */
}
else if (found == 1) { /* device is different kind */
changes++;
printk("cciss%d: device c%db%dt%dl%d type changed "
"(device type now %s).\n",
ctlr, hostno, csd->bus, csd->target, csd->lun,
- DEVICETYPE(csd->devtype));
+ scsi_device_type(csd->devtype));
+ cciss_scsi_remove_entry(ctlr, hostno, i,
+ removed, &nremoved);
+ /* remove ^^^, hence i not incremented */
+ if (cciss_scsi_add_entry(ctlr, hostno,
+ &sd[j].scsi3addr[0], sd[j].devtype,
+ added, &nadded) != 0)
+ /* we just removed one, so add can't fail. */
+ BUG();
csd->devtype = sd[j].devtype;
- i++; /* so just move along. */
} else /* device is same as it ever was, */
i++; /* so just move along. */
}
if (!found) {
changes++;
if (cciss_scsi_add_entry(ctlr, hostno,
- &sd[i].scsi3addr[0], sd[i].devtype) != 0)
+
+ &sd[i].scsi3addr[0], sd[i].devtype,
+ added, &nadded) != 0)
break;
} else if (found == 1) {
/* should never happen... */
}
CPQ_TAPE_UNLOCK(ctlr, flags);
- if (!changes)
- printk("cciss%d: No device changes detected.\n", ctlr);
+ /* Don't notify scsi mid layer of any changes the first time through */
+ /* (or if there are no changes) scsi_scan_host will do it later the */
+ /* first time through. */
+ if (hostno == -1 || !changes)
+ goto free_and_out;
+
+ /* Notify scsi mid layer of any removed devices */
+ for (i = 0; i < nremoved; i++) {
+ struct scsi_device *sdev =
+ scsi_device_lookup(sh, removed[i].bus,
+ removed[i].target, removed[i].lun);
+ if (sdev != NULL) {
+ scsi_remove_device(sdev);
+ scsi_device_put(sdev);
+ } else {
+ /* We don't expect to get here. */
+ /* future cmds to this device will get selection */
+ /* timeout as if the device was gone. */
+ printk(KERN_WARNING "cciss%d: didn't find "
+ "c%db%dt%dl%d\n for removal.",
+ ctlr, hostno, removed[i].bus,
+ removed[i].target, removed[i].lun);
+ }
+ }
+ /* Notify scsi mid layer of any added devices */
+ for (i = 0; i < nadded; i++) {
+ int rc;
+ rc = scsi_add_device(sh, added[i].bus,
+ added[i].target, added[i].lun);
+ if (rc == 0)
+ continue;
+ printk(KERN_WARNING "cciss%d: scsi_add_device "
+ "c%db%dt%dl%d failed, device not added.\n",
+ ctlr, hostno,
+ added[i].bus, added[i].target, added[i].lun);
+ /* now we have to remove it from ccissscsi, */
+ /* since it didn't get added to scsi mid layer */
+ fixup_botched_add(ctlr, added[i].scsi3addr);
+ }
+
+free_and_out:
+ kfree(added);
+ kfree(removed);
return 0;
}
{
struct scsi_cmnd *cmd;
ctlr_info_t *ctlr;
- u64bit addr64;
ErrorInfo_struct *ei;
ei = cp->err_info;
cmd = (struct scsi_cmnd *) cp->scsi_cmd;
ctlr = hba[cp->ctlr];
- /* undo the DMA mappings */
-
- if (cmd->use_sg) {
- pci_unmap_sg(ctlr->pdev,
- cmd->buffer, cmd->use_sg,
- cmd->sc_data_direction);
- }
- else if (cmd->request_bufflen) {
- addr64.val32.lower = cp->SG[0].Addr.lower;
- addr64.val32.upper = cp->SG[0].Addr.upper;
- pci_unmap_single(ctlr->pdev, (dma_addr_t) addr64.val,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
ei->SenseLen > SCSI_SENSE_BUFFERSIZE ?
SCSI_SENSE_BUFFERSIZE :
ei->SenseLen);
- cmd->resid = ei->ResidualCnt;
+ scsi_set_resid(cmd, ei->ResidualCnt);
if(ei->CommandStatus != 0)
{ /* an error has occurred */
((struct cciss_scsi_adapter_data_t *)
hba[ctlr]->scsi_ctlr)->scsi_host = (void *) sh;
sh->hostdata[0] = (unsigned long) hba[ctlr];
- sh->irq = hba[ctlr]->intr;
+ sh->irq = hba[ctlr]->intr[SIMPLE_MODE_INT];
sh->unique_id = sh->irq;
error = scsi_add_host(sh, &hba[ctlr]->pdev->dev);
if (error)
int direction)
{
unsigned long flags;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
cp->cmd_type = CMD_IOCTL_PEND; // treat this like an ioctl
cp->scsi_cmd = NULL;
int i;
c = (ctlr_info_t *) hba[cntl_num];
- ld_buff = kmalloc(reportlunsize, GFP_KERNEL);
+ ld_buff = kzalloc(reportlunsize, GFP_KERNEL);
if (ld_buff == NULL) {
printk(KERN_ERR "cciss: out of memory\n");
return;
}
- memset(ld_buff, 0, reportlunsize);
inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
if (inq_buff == NULL) {
printk(KERN_ERR "cciss: out of memory\n");
if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
printk(KERN_INFO "cciss%d: %s ignored, "
"too many devices.\n", cntl_num,
- DEVICETYPE(devtype));
+ scsi_device_type(devtype));
break;
}
memcpy(¤tsd[ncurrent].scsi3addr[0],
int buflen, datalen;
ctlr_info_t *ci;
+ int i;
int cntl_num;
cntl_num = ci->ctlr; /* Get our index into the hba[] array */
if (func == 0) { /* User is reading from /proc/scsi/ciss*?/?* */
- buflen = sprintf(buffer, "hostnum=%d\n", sh->host_no);
-
+ buflen = sprintf(buffer, "cciss%d: SCSI host: %d\n",
+ cntl_num, sh->host_no);
+
+ /* this information is needed by apps to know which cciss
+ device corresponds to which scsi host number without
+ having to open a scsi target device node. The device
+ information is not a duplicate of /proc/scsi/scsi because
+ the two may be out of sync due to scsi hotplug, rather
+ this info is for an app to be able to use to know how to
+ get them back in sync. */
+
+ for (i=0;i<ccissscsi[cntl_num].ndevices;i++) {
+ struct cciss_scsi_dev_t *sd = &ccissscsi[cntl_num].dev[i];
+ buflen += sprintf(&buffer[buflen], "c%db%dt%dl%d %02d "
+ "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ sh->host_no, sd->bus, sd->target, sd->lun,
+ sd->devtype,
+ sd->scsi3addr[0], sd->scsi3addr[1],
+ sd->scsi3addr[2], sd->scsi3addr[3],
+ sd->scsi3addr[4], sd->scsi3addr[5],
+ sd->scsi3addr[6], sd->scsi3addr[7]);
+ }
datalen = buflen - offset;
if (datalen < 0) { /* they're reading past EOF. */
datalen = 0;
CommandList_struct *cp,
struct scsi_cmnd *cmd)
{
- unsigned int use_sg, nsegs=0, len;
- struct scatterlist *scatter = (struct scatterlist *) cmd->buffer;
+ unsigned int len;
+ struct scatterlist *sg;
__u64 addr64;
-
- /* is it just one virtual address? */
- if (!cmd->use_sg) {
- if (cmd->request_bufflen) { /* anything to xfer? */
-
- addr64 = (__u64) pci_map_single(pdev,
- cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
-
- cp->SG[0].Addr.lower =
- (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
- cp->SG[0].Addr.upper =
- (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
- cp->SG[0].Len = cmd->request_bufflen;
- nsegs=1;
+ int use_sg, i;
+
+ BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);
+
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg) { /* not too many addrs? */
+ scsi_for_each_sg(cmd, sg, use_sg, i) {
+ addr64 = (__u64) sg_dma_address(sg);
+ len = sg_dma_len(sg);
+ cp->SG[i].Addr.lower =
+ (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[i].Addr.upper =
+ (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[i].Len = len;
+ cp->SG[i].Ext = 0; // we are not chaining
}
- } /* else, must be a list of virtual addresses.... */
- else if (cmd->use_sg <= MAXSGENTRIES) { /* not too many addrs? */
-
- use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg,
- cmd->sc_data_direction);
-
- for (nsegs=0; nsegs < use_sg; nsegs++) {
- addr64 = (__u64) sg_dma_address(&scatter[nsegs]);
- len = sg_dma_len(&scatter[nsegs]);
- cp->SG[nsegs].Addr.lower =
- (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
- cp->SG[nsegs].Addr.upper =
- (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
- cp->SG[nsegs].Len = len;
- cp->SG[nsegs].Ext = 0; // we are not chaining
- }
- } else BUG();
+ }
- cp->Header.SGList = (__u8) nsegs; /* no. SGs contig in this cmd */
- cp->Header.SGTotal = (__u16) nsegs; /* total sgs in this cmd list */
+ cp->Header.SGList = (__u8) use_sg; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = (__u16) use_sg; /* total sgs in this cmd list */
return;
}
cp->Request.Timeout = 0;
memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
- if (cmd->cmd_len > sizeof(cp->Request.CDB)) BUG();
+ BUG_ON(cmd->cmd_len > sizeof(cp->Request.CDB));
cp->Request.CDBLen = cmd->cmd_len;
memcpy(cp->Request.CDB, cmd->cmnd, cmd->cmd_len);
cp->Request.Type.Type = TYPE_CMD;
/* set scsi_host to NULL so our detect routine will
find us on register */
sa->scsi_host = NULL;
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
scsi_cmd_stack_free(ctlr);
kfree(sa);
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-}
-
-static int
-cciss_register_scsi(int ctlr)
-{
- unsigned long flags;
-
- CPQ_TAPE_LOCK(ctlr, flags);
-
- /* Since this is really a block driver, the SCSI core may not be
- initialized at init time, in which case, calling scsi_register_host
- would hang. Instead, we do it later, via /proc filesystem
- and rc scripts, when we know SCSI core is good to go. */
-
- /* Only register if SCSI devices are detected. */
- if (ccissscsi[ctlr].ndevices != 0) {
- ((struct cciss_scsi_adapter_data_t *)
- hba[ctlr]->scsi_ctlr)->registered = 1;
- CPQ_TAPE_UNLOCK(ctlr, flags);
- return cciss_scsi_detect(ctlr);
- }
- CPQ_TAPE_UNLOCK(ctlr, flags);
- printk(KERN_INFO
- "cciss%d: No appropriate SCSI device detected, "
- "SCSI subsystem not engaged.\n", ctlr);
- return 0;
}
static int
sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
stk = &sa->cmd_stack;
- if (((struct cciss_scsi_adapter_data_t *)
- hba[ctlr]->scsi_ctlr)->registered) {
+ if (sa->registered) {
printk("cciss%d: SCSI subsystem already engaged.\n", ctlr);
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
return ENXIO;
}
+ sa->registered = 1;
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
cciss_update_non_disk_devices(ctlr, -1);
- cciss_register_scsi(ctlr);
+ cciss_scsi_detect(ctlr);
return 0;
}
static void
-cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
+cciss_seq_tape_report(struct seq_file *seq, int ctlr)
{
unsigned long flags;
- int size;
-
- *pos = *pos -1; *len = *len - 1; // cut off the last trailing newline
CPQ_TAPE_LOCK(ctlr, flags);
- size = sprintf(buffer + *len,
- " Sequential access devices: %d\n\n",
+ seq_printf(seq,
+ "Sequential access devices: %d\n\n",
ccissscsi[ctlr].ndevices);
CPQ_TAPE_UNLOCK(ctlr, flags);
- *pos += size; *len += size;
+}
+
+
+/* Need at least one of these error handlers to keep ../scsi/hosts.c from
+ * complaining. Doing a host- or bus-reset can't do anything good here.
+ * Despite what it might say in scsi_error.c, there may well be commands
+ * on the controller, as the cciss driver registers twice, once as a block
+ * device for the logical drives, and once as a scsi device, for any tape
+ * drives. So we know there are no commands out on the tape drives, but we
+ * don't know there are no commands on the controller, and it is likely
+ * that there probably are, as the cciss block device is most commonly used
+ * as a boot device (embedded controller on HP/Compaq systems.)
+*/
+
+static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
+{
+ int rc;
+ CommandList_struct *cmd_in_trouble;
+ ctlr_info_t **c;
+ int ctlr;
+
+ /* find the controller to which the command to be aborted was sent */
+ c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];
+ if (c == NULL) /* paranoia */
+ return FAILED;
+ ctlr = (*c)->ctlr;
+ printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr);
+
+ /* find the command that's giving us trouble */
+ cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble;
+ if (cmd_in_trouble == NULL) { /* paranoia */
+ return FAILED;
+ }
+ /* send a reset to the SCSI LUN which the command was sent to */
+ rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0,
+ (unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0],
+ TYPE_MSG);
+ /* sendcmd turned off interrupts on the board, turn 'em back on. */
+ (*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
+ if (rc == 0)
+ return SUCCESS;
+ printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr);
+ return FAILED;
+}
+
+static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd)
+{
+ int rc;
+ CommandList_struct *cmd_to_abort;
+ ctlr_info_t **c;
+ int ctlr;
+
+ /* find the controller to which the command to be aborted was sent */
+ c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];
+ if (c == NULL) /* paranoia */
+ return FAILED;
+ ctlr = (*c)->ctlr;
+ printk(KERN_WARNING "cciss%d: aborting tardy SCSI cmd\n", ctlr);
+
+ /* find the command to be aborted */
+ cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble;
+ if (cmd_to_abort == NULL) /* paranoia */
+ return FAILED;
+ rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag,
+ 0, 2, 0, 0,
+ (unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0],
+ TYPE_MSG);
+ /* sendcmd turned off interrupts on the board, turn 'em back on. */
+ (*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
+ if (rc == 0)
+ return SUCCESS;
+ return FAILED;
+
}
#else /* no CONFIG_CISS_SCSI_TAPE */
/* If no tape support, then these become defined out of existence */
#define cciss_scsi_setup(cntl_num)
-#define cciss_unregister_scsi(ctlr)
-#define cciss_register_scsi(ctlr)
-#define cciss_proc_tape_report(ctlr, buffer, pos, len)
#endif /* CONFIG_CISS_SCSI_TAPE */