diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/cciss.c | 188 | ||||
-rw-r--r-- | drivers/block/cciss.h | 11 | ||||
-rw-r--r-- | drivers/block/cciss_scsi.c | 82 |
3 files changed, 254 insertions, 27 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 486b6e1c7dfb..482786068ff9 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -148,6 +148,7 @@ static struct board_type products[] = { | |||
148 | static ctlr_info_t *hba[MAX_CTLR]; | 148 | static ctlr_info_t *hba[MAX_CTLR]; |
149 | 149 | ||
150 | static void do_cciss_request(request_queue_t *q); | 150 | static void do_cciss_request(request_queue_t *q); |
151 | static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs); | ||
151 | static int cciss_open(struct inode *inode, struct file *filep); | 152 | static int cciss_open(struct inode *inode, struct file *filep); |
152 | static int cciss_release(struct inode *inode, struct file *filep); | 153 | static int cciss_release(struct inode *inode, struct file *filep); |
153 | static int cciss_ioctl(struct inode *inode, struct file *filep, | 154 | static int cciss_ioctl(struct inode *inode, struct file *filep, |
@@ -1586,6 +1587,24 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, | |||
1586 | } | 1587 | } |
1587 | } else if (cmd_type == TYPE_MSG) { | 1588 | } else if (cmd_type == TYPE_MSG) { |
1588 | switch (cmd) { | 1589 | switch (cmd) { |
1590 | case 0: /* ABORT message */ | ||
1591 | c->Request.CDBLen = 12; | ||
1592 | c->Request.Type.Attribute = ATTR_SIMPLE; | ||
1593 | c->Request.Type.Direction = XFER_WRITE; | ||
1594 | c->Request.Timeout = 0; | ||
1595 | c->Request.CDB[0] = cmd; /* abort */ | ||
1596 | c->Request.CDB[1] = 0; /* abort a command */ | ||
1597 | /* buff contains the tag of the command to abort */ | ||
1598 | memcpy(&c->Request.CDB[4], buff, 8); | ||
1599 | break; | ||
1600 | case 1: /* RESET message */ | ||
1601 | c->Request.CDBLen = 12; | ||
1602 | c->Request.Type.Attribute = ATTR_SIMPLE; | ||
1603 | c->Request.Type.Direction = XFER_WRITE; | ||
1604 | c->Request.Timeout = 0; | ||
1605 | memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB)); | ||
1606 | c->Request.CDB[0] = cmd; /* reset */ | ||
1607 | c->Request.CDB[1] = 0x04; /* reset a LUN */ | ||
1589 | case 3: /* No-Op message */ | 1608 | case 3: /* No-Op message */ |
1590 | c->Request.CDBLen = 1; | 1609 | c->Request.CDBLen = 1; |
1591 | c->Request.Type.Attribute = ATTR_SIMPLE; | 1610 | c->Request.Type.Attribute = ATTR_SIMPLE; |
@@ -1872,6 +1891,52 @@ static unsigned long pollcomplete(int ctlr) | |||
1872 | /* Invalid address to tell caller we ran out of time */ | 1891 | /* Invalid address to tell caller we ran out of time */ |
1873 | return 1; | 1892 | return 1; |
1874 | } | 1893 | } |
1894 | |||
1895 | static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete) | ||
1896 | { | ||
1897 | /* We get in here if sendcmd() is polling for completions | ||
1898 | and gets some command back that it wasn't expecting -- | ||
1899 | something other than that which it just sent down. | ||
1900 | Ordinarily, that shouldn't happen, but it can happen when | ||
1901 | the scsi tape stuff gets into error handling mode, and | ||
1902 | starts using sendcmd() to try to abort commands and | ||
1903 | reset tape drives. In that case, sendcmd may pick up | ||
1904 | completions of commands that were sent to logical drives | ||
1905 | through the block i/o system, or cciss ioctls completing, etc. | ||
1906 | In that case, we need to save those completions for later | ||
1907 | processing by the interrupt handler. | ||
1908 | */ | ||
1909 | |||
1910 | #ifdef CONFIG_CISS_SCSI_TAPE | ||
1911 | struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects; | ||
1912 | |||
1913 | /* If it's not the scsi tape stuff doing error handling, (abort */ | ||
1914 | /* or reset) then we don't expect anything weird. */ | ||
1915 | if (cmd != CCISS_RESET_MSG && cmd != CCISS_ABORT_MSG) { | ||
1916 | #endif | ||
1917 | printk( KERN_WARNING "cciss cciss%d: SendCmd " | ||
1918 | "Invalid command list address returned! (%lx)\n", | ||
1919 | ctlr, complete); | ||
1920 | /* not much we can do. */ | ||
1921 | #ifdef CONFIG_CISS_SCSI_TAPE | ||
1922 | return 1; | ||
1923 | } | ||
1924 | |||
1925 | /* We've sent down an abort or reset, but something else | ||
1926 | has completed */ | ||
1927 | if (srl->ncompletions >= (NR_CMDS + 2)) { | ||
1928 | /* Uh oh. No room to save it for later... */ | ||
1929 | printk(KERN_WARNING "cciss%d: Sendcmd: Invalid command addr, " | ||
1930 | "reject list overflow, command lost!\n", ctlr); | ||
1931 | return 1; | ||
1932 | } | ||
1933 | /* Save it for later */ | ||
1934 | srl->complete[srl->ncompletions] = complete; | ||
1935 | srl->ncompletions++; | ||
1936 | #endif | ||
1937 | return 0; | ||
1938 | } | ||
1939 | |||
1875 | /* | 1940 | /* |
1876 | * Send a command to the controller, and wait for it to complete. | 1941 | * Send a command to the controller, and wait for it to complete. |
1877 | * Only used at init time. | 1942 | * Only used at init time. |
@@ -1894,7 +1959,7 @@ static int sendcmd( | |||
1894 | unsigned long complete; | 1959 | unsigned long complete; |
1895 | ctlr_info_t *info_p= hba[ctlr]; | 1960 | ctlr_info_t *info_p= hba[ctlr]; |
1896 | u64bit buff_dma_handle; | 1961 | u64bit buff_dma_handle; |
1897 | int status; | 1962 | int status, done = 0; |
1898 | 1963 | ||
1899 | if ((c = cmd_alloc(info_p, 1)) == NULL) { | 1964 | if ((c = cmd_alloc(info_p, 1)) == NULL) { |
1900 | printk(KERN_WARNING "cciss: unable to get memory"); | 1965 | printk(KERN_WARNING "cciss: unable to get memory"); |
@@ -1916,7 +1981,9 @@ resend_cmd1: | |||
1916 | info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF); | 1981 | info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF); |
1917 | 1982 | ||
1918 | /* Make sure there is room in the command FIFO */ | 1983 | /* Make sure there is room in the command FIFO */ |
1919 | /* Actually it should be completely empty at this time. */ | 1984 | /* Actually it should be completely empty at this time */ |
1985 | /* unless we are in here doing error handling for the scsi */ | ||
1986 | /* tape side of the driver. */ | ||
1920 | for (i = 200000; i > 0; i--) | 1987 | for (i = 200000; i > 0; i--) |
1921 | { | 1988 | { |
1922 | /* if fifo isn't full go */ | 1989 | /* if fifo isn't full go */ |
@@ -1933,13 +2000,25 @@ resend_cmd1: | |||
1933 | * Send the cmd | 2000 | * Send the cmd |
1934 | */ | 2001 | */ |
1935 | info_p->access.submit_command(info_p, c); | 2002 | info_p->access.submit_command(info_p, c); |
1936 | complete = pollcomplete(ctlr); | 2003 | done = 0; |
2004 | do { | ||
2005 | complete = pollcomplete(ctlr); | ||
1937 | 2006 | ||
1938 | #ifdef CCISS_DEBUG | 2007 | #ifdef CCISS_DEBUG |
1939 | printk(KERN_DEBUG "cciss: command completed\n"); | 2008 | printk(KERN_DEBUG "cciss: command completed\n"); |
1940 | #endif /* CCISS_DEBUG */ | 2009 | #endif /* CCISS_DEBUG */ |
1941 | 2010 | ||
1942 | if (complete != 1) { | 2011 | if (complete == 1) { |
2012 | printk( KERN_WARNING | ||
2013 | "cciss cciss%d: SendCmd Timeout out, " | ||
2014 | "No command list address returned!\n", | ||
2015 | ctlr); | ||
2016 | status = IO_ERROR; | ||
2017 | done = 1; | ||
2018 | break; | ||
2019 | } | ||
2020 | |||
2021 | /* This will need to change for direct lookup completions */ | ||
1943 | if ( (complete & CISS_ERROR_BIT) | 2022 | if ( (complete & CISS_ERROR_BIT) |
1944 | && (complete & ~CISS_ERROR_BIT) == c->busaddr) | 2023 | && (complete & ~CISS_ERROR_BIT) == c->busaddr) |
1945 | { | 2024 | { |
@@ -1979,6 +2058,10 @@ resend_cmd1: | |||
1979 | status = IO_ERROR; | 2058 | status = IO_ERROR; |
1980 | goto cleanup1; | 2059 | goto cleanup1; |
1981 | } | 2060 | } |
2061 | } else if (c->err_info->CommandStatus == CMD_UNABORTABLE) { | ||
2062 | printk(KERN_WARNING "cciss%d: command could not be aborted.\n", ctlr); | ||
2063 | status = IO_ERROR; | ||
2064 | goto cleanup1; | ||
1982 | } | 2065 | } |
1983 | printk(KERN_WARNING "ciss ciss%d: sendcmd" | 2066 | printk(KERN_WARNING "ciss ciss%d: sendcmd" |
1984 | " Error %x \n", ctlr, | 2067 | " Error %x \n", ctlr, |
@@ -1993,20 +2076,15 @@ resend_cmd1: | |||
1993 | goto cleanup1; | 2076 | goto cleanup1; |
1994 | } | 2077 | } |
1995 | } | 2078 | } |
2079 | /* This will need changing for direct lookup completions */ | ||
1996 | if (complete != c->busaddr) { | 2080 | if (complete != c->busaddr) { |
1997 | printk( KERN_WARNING "cciss cciss%d: SendCmd " | 2081 | if (add_sendcmd_reject(cmd, ctlr, complete) != 0) { |
1998 | "Invalid command list address returned! (%lx)\n", | 2082 | BUG(); /* we are pretty much hosed if we get here. */ |
1999 | ctlr, complete); | 2083 | } |
2000 | status = IO_ERROR; | 2084 | continue; |
2001 | goto cleanup1; | 2085 | } else |
2002 | } | 2086 | done = 1; |
2003 | } else { | 2087 | } while (!done); |
2004 | printk( KERN_WARNING | ||
2005 | "cciss cciss%d: SendCmd Timeout out, " | ||
2006 | "No command list address returned!\n", | ||
2007 | ctlr); | ||
2008 | status = IO_ERROR; | ||
2009 | } | ||
2010 | 2088 | ||
2011 | cleanup1: | 2089 | cleanup1: |
2012 | /* unlock the data buffer from DMA */ | 2090 | /* unlock the data buffer from DMA */ |
@@ -2014,6 +2092,11 @@ cleanup1: | |||
2014 | buff_dma_handle.val32.upper = c->SG[0].Addr.upper; | 2092 | buff_dma_handle.val32.upper = c->SG[0].Addr.upper; |
2015 | pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val, | 2093 | pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val, |
2016 | c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); | 2094 | c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); |
2095 | #ifdef CONFIG_CISS_SCSI_TAPE | ||
2096 | /* if we saved some commands for later, process them now. */ | ||
2097 | if (info_p->scsi_rejects.ncompletions > 0) | ||
2098 | do_cciss_intr(0, info_p, NULL); | ||
2099 | #endif | ||
2017 | cmd_free(info_p, c, 1); | 2100 | cmd_free(info_p, c, 1); |
2018 | return (status); | 2101 | return (status); |
2019 | } | 2102 | } |
@@ -2338,6 +2421,48 @@ startio: | |||
2338 | start_io(h); | 2421 | start_io(h); |
2339 | } | 2422 | } |
2340 | 2423 | ||
2424 | static inline unsigned long get_next_completion(ctlr_info_t *h) | ||
2425 | { | ||
2426 | #ifdef CONFIG_CISS_SCSI_TAPE | ||
2427 | /* Any rejects from sendcmd() lying around? Process them first */ | ||
2428 | if (h->scsi_rejects.ncompletions == 0) | ||
2429 | return h->access.command_completed(h); | ||
2430 | else { | ||
2431 | struct sendcmd_reject_list *srl; | ||
2432 | int n; | ||
2433 | srl = &h->scsi_rejects; | ||
2434 | n = --srl->ncompletions; | ||
2435 | /* printk("cciss%d: processing saved reject\n", h->ctlr); */ | ||
2436 | printk("p"); | ||
2437 | return srl->complete[n]; | ||
2438 | } | ||
2439 | #else | ||
2440 | return h->access.command_completed(h); | ||
2441 | #endif | ||
2442 | } | ||
2443 | |||
2444 | static inline int interrupt_pending(ctlr_info_t *h) | ||
2445 | { | ||
2446 | #ifdef CONFIG_CISS_SCSI_TAPE | ||
2447 | return ( h->access.intr_pending(h) | ||
2448 | || (h->scsi_rejects.ncompletions > 0)); | ||
2449 | #else | ||
2450 | return h->access.intr_pending(h); | ||
2451 | #endif | ||
2452 | } | ||
2453 | |||
2454 | static inline long interrupt_not_for_us(ctlr_info_t *h) | ||
2455 | { | ||
2456 | #ifdef CONFIG_CISS_SCSI_TAPE | ||
2457 | return (((h->access.intr_pending(h) == 0) || | ||
2458 | (h->interrupts_enabled == 0)) | ||
2459 | && (h->scsi_rejects.ncompletions == 0)); | ||
2460 | #else | ||
2461 | return (((h->access.intr_pending(h) == 0) || | ||
2462 | (h->interrupts_enabled == 0))); | ||
2463 | #endif | ||
2464 | } | ||
2465 | |||
2341 | static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) | 2466 | static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) |
2342 | { | 2467 | { |
2343 | ctlr_info_t *h = dev_id; | 2468 | ctlr_info_t *h = dev_id; |
@@ -2347,19 +2472,15 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) | |||
2347 | int j; | 2472 | int j; |
2348 | int start_queue = h->next_to_run; | 2473 | int start_queue = h->next_to_run; |
2349 | 2474 | ||
2350 | /* Is this interrupt for us? */ | 2475 | if (interrupt_not_for_us(h)) |
2351 | if (( h->access.intr_pending(h) == 0) || (h->interrupts_enabled == 0)) | ||
2352 | return IRQ_NONE; | 2476 | return IRQ_NONE; |
2353 | |||
2354 | /* | 2477 | /* |
2355 | * If there are completed commands in the completion queue, | 2478 | * If there are completed commands in the completion queue, |
2356 | * we had better do something about it. | 2479 | * we had better do something about it. |
2357 | */ | 2480 | */ |
2358 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | 2481 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); |
2359 | while( h->access.intr_pending(h)) | 2482 | while (interrupt_pending(h)) { |
2360 | { | 2483 | while((a = get_next_completion(h)) != FIFO_EMPTY) { |
2361 | while((a = h->access.command_completed(h)) != FIFO_EMPTY) | ||
2362 | { | ||
2363 | a1 = a; | 2484 | a1 = a; |
2364 | if ((a & 0x04)) { | 2485 | if ((a & 0x04)) { |
2365 | a2 = (a >> 3); | 2486 | a2 = (a >> 3); |
@@ -2966,7 +3087,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
2966 | printk( KERN_ERR "cciss: out of memory"); | 3087 | printk( KERN_ERR "cciss: out of memory"); |
2967 | goto clean4; | 3088 | goto clean4; |
2968 | } | 3089 | } |
2969 | 3090 | #ifdef CONFIG_CISS_SCSI_TAPE | |
3091 | hba[i]->scsi_rejects.complete = | ||
3092 | kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) * | ||
3093 | (NR_CMDS + 5), GFP_KERNEL); | ||
3094 | if (hba[i]->scsi_rejects.complete == NULL) { | ||
3095 | printk( KERN_ERR "cciss: out of memory"); | ||
3096 | goto clean4; | ||
3097 | } | ||
3098 | #endif | ||
2970 | spin_lock_init(&hba[i]->lock); | 3099 | spin_lock_init(&hba[i]->lock); |
2971 | 3100 | ||
2972 | /* Initialize the pdev driver private data. | 3101 | /* Initialize the pdev driver private data. |
@@ -3034,6 +3163,10 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
3034 | return(1); | 3163 | return(1); |
3035 | 3164 | ||
3036 | clean4: | 3165 | clean4: |
3166 | #ifdef CONFIG_CISS_SCSI_TAPE | ||
3167 | if(hba[i]->scsi_rejects.complete) | ||
3168 | kfree(hba[i]->scsi_rejects.complete); | ||
3169 | #endif | ||
3037 | if(hba[i]->cmd_pool_bits) | 3170 | if(hba[i]->cmd_pool_bits) |
3038 | kfree(hba[i]->cmd_pool_bits); | 3171 | kfree(hba[i]->cmd_pool_bits); |
3039 | if(hba[i]->cmd_pool) | 3172 | if(hba[i]->cmd_pool) |
@@ -3107,6 +3240,9 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) | |||
3107 | pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), | 3240 | pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), |
3108 | hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle); | 3241 | hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle); |
3109 | kfree(hba[i]->cmd_pool_bits); | 3242 | kfree(hba[i]->cmd_pool_bits); |
3243 | #ifdef CONFIG_CISS_SCSI_TAPE | ||
3244 | kfree(hba[i]->scsi_rejects.complete); | ||
3245 | #endif | ||
3110 | release_io_mem(hba[i]); | 3246 | release_io_mem(hba[i]); |
3111 | free_hba(i); | 3247 | free_hba(i); |
3112 | } | 3248 | } |
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index ef277baee9fd..3b0858c83897 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h | |||
@@ -44,6 +44,14 @@ typedef struct _drive_info_struct | |||
44 | */ | 44 | */ |
45 | } drive_info_struct; | 45 | } drive_info_struct; |
46 | 46 | ||
47 | #ifdef CONFIG_CISS_SCSI_TAPE | ||
48 | |||
49 | struct sendcmd_reject_list { | ||
50 | int ncompletions; | ||
51 | unsigned long *complete; /* array of NR_CMDS tags */ | ||
52 | }; | ||
53 | |||
54 | #endif | ||
47 | struct ctlr_info | 55 | struct ctlr_info |
48 | { | 56 | { |
49 | int ctlr; | 57 | int ctlr; |
@@ -100,6 +108,9 @@ struct ctlr_info | |||
100 | struct gendisk *gendisk[NWD]; | 108 | struct gendisk *gendisk[NWD]; |
101 | #ifdef CONFIG_CISS_SCSI_TAPE | 109 | #ifdef CONFIG_CISS_SCSI_TAPE |
102 | void *scsi_ctlr; /* ptr to structure containing scsi related stuff */ | 110 | void *scsi_ctlr; /* ptr to structure containing scsi related stuff */ |
111 | /* list of block side commands the scsi error handling sucked up */ | ||
112 | /* and saved for later processing */ | ||
113 | struct sendcmd_reject_list scsi_rejects; | ||
103 | #endif | 114 | #endif |
104 | unsigned char alive; | 115 | unsigned char alive; |
105 | }; | 116 | }; |
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index ec27976a57da..3226aa11c6ef 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c | |||
@@ -42,6 +42,9 @@ | |||
42 | 42 | ||
43 | #include "cciss_scsi.h" | 43 | #include "cciss_scsi.h" |
44 | 44 | ||
45 | #define CCISS_ABORT_MSG 0x00 | ||
46 | #define CCISS_RESET_MSG 0x01 | ||
47 | |||
45 | /* some prototypes... */ | 48 | /* some prototypes... */ |
46 | static int sendcmd( | 49 | static int sendcmd( |
47 | __u8 cmd, | 50 | __u8 cmd, |
@@ -67,6 +70,8 @@ static int cciss_scsi_proc_info( | |||
67 | 70 | ||
68 | static int cciss_scsi_queue_command (struct scsi_cmnd *cmd, | 71 | static int cciss_scsi_queue_command (struct scsi_cmnd *cmd, |
69 | void (* done)(struct scsi_cmnd *)); | 72 | void (* done)(struct scsi_cmnd *)); |
73 | static int cciss_eh_device_reset_handler(struct scsi_cmnd *); | ||
74 | static int cciss_eh_abort_handler(struct scsi_cmnd *); | ||
70 | 75 | ||
71 | static struct cciss_scsi_hba_t ccissscsi[MAX_CTLR] = { | 76 | static struct cciss_scsi_hba_t ccissscsi[MAX_CTLR] = { |
72 | { .name = "cciss0", .ndevices = 0 }, | 77 | { .name = "cciss0", .ndevices = 0 }, |
@@ -90,6 +95,9 @@ static struct scsi_host_template cciss_driver_template = { | |||
90 | .sg_tablesize = MAXSGENTRIES, | 95 | .sg_tablesize = MAXSGENTRIES, |
91 | .cmd_per_lun = 1, | 96 | .cmd_per_lun = 1, |
92 | .use_clustering = DISABLE_CLUSTERING, | 97 | .use_clustering = DISABLE_CLUSTERING, |
98 | /* Can't have eh_bus_reset_handler or eh_host_reset_handler for cciss */ | ||
99 | .eh_device_reset_handler= cciss_eh_device_reset_handler, | ||
100 | .eh_abort_handler = cciss_eh_abort_handler, | ||
93 | }; | 101 | }; |
94 | 102 | ||
95 | #pragma pack(1) | 103 | #pragma pack(1) |
@@ -247,7 +255,7 @@ scsi_cmd_stack_free(int ctlr) | |||
247 | #define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \ | 255 | #define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \ |
248 | "Unknown" : scsi_device_types[n] | 256 | "Unknown" : scsi_device_types[n] |
249 | 257 | ||
250 | #if 0 | 258 | #if 1 |
251 | static int xmargin=8; | 259 | static int xmargin=8; |
252 | static int amargin=60; | 260 | static int amargin=60; |
253 | 261 | ||
@@ -1448,6 +1456,78 @@ cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len) | |||
1448 | *pos += size; *len += size; | 1456 | *pos += size; *len += size; |
1449 | } | 1457 | } |
1450 | 1458 | ||
1459 | /* Need at least one of these error handlers to keep ../scsi/hosts.c from | ||
1460 | * complaining. Doing a host- or bus-reset can't do anything good here. | ||
1461 | * Despite what it might say in scsi_error.c, there may well be commands | ||
1462 | * on the controller, as the cciss driver registers twice, once as a block | ||
1463 | * device for the logical drives, and once as a scsi device, for any tape | ||
1464 | * drives. So we know there are no commands out on the tape drives, but we | ||
1465 | * don't know there are no commands on the controller, and it is likely | ||
1466 | * that there probably are, as the cciss block device is most commonly used | ||
1467 | * as a boot device (embedded controller on HP/Compaq systems.) | ||
1468 | */ | ||
1469 | |||
1470 | static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) | ||
1471 | { | ||
1472 | int rc; | ||
1473 | CommandList_struct *cmd_in_trouble; | ||
1474 | ctlr_info_t **c; | ||
1475 | int ctlr; | ||
1476 | |||
1477 | /* find the controller to which the command to be aborted was sent */ | ||
1478 | c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0]; | ||
1479 | if (c == NULL) /* paranoia */ | ||
1480 | return FAILED; | ||
1481 | ctlr = (*c)->ctlr; | ||
1482 | printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr); | ||
1483 | |||
1484 | /* find the command that's giving us trouble */ | ||
1485 | cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble; | ||
1486 | if (cmd_in_trouble == NULL) { /* paranoia */ | ||
1487 | return FAILED; | ||
1488 | } | ||
1489 | /* send a reset to the SCSI LUN which the command was sent to */ | ||
1490 | rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, | ||
1491 | (unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0], | ||
1492 | TYPE_MSG); | ||
1493 | /* sendcmd turned off interrputs on the board, turn 'em back on. */ | ||
1494 | (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); | ||
1495 | if (rc == 0) | ||
1496 | return SUCCESS; | ||
1497 | printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr); | ||
1498 | return FAILED; | ||
1499 | } | ||
1500 | |||
1501 | static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) | ||
1502 | { | ||
1503 | int rc; | ||
1504 | CommandList_struct *cmd_to_abort; | ||
1505 | ctlr_info_t **c; | ||
1506 | int ctlr; | ||
1507 | |||
1508 | /* find the controller to which the command to be aborted was sent */ | ||
1509 | c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0]; | ||
1510 | if (c == NULL) /* paranoia */ | ||
1511 | return FAILED; | ||
1512 | ctlr = (*c)->ctlr; | ||
1513 | printk(KERN_WARNING "cciss%d: aborting tardy SCSI cmd\n", ctlr); | ||
1514 | |||
1515 | /* find the command to be aborted */ | ||
1516 | cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble; | ||
1517 | if (cmd_to_abort == NULL) /* paranoia */ | ||
1518 | return FAILED; | ||
1519 | rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, | ||
1520 | 0, 2, 0, 0, | ||
1521 | (unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0], | ||
1522 | TYPE_MSG); | ||
1523 | /* sendcmd turned off interrputs on the board, turn 'em back on. */ | ||
1524 | (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); | ||
1525 | if (rc == 0) | ||
1526 | return SUCCESS; | ||
1527 | return FAILED; | ||
1528 | |||
1529 | } | ||
1530 | |||
1451 | #else /* no CONFIG_CISS_SCSI_TAPE */ | 1531 | #else /* no CONFIG_CISS_SCSI_TAPE */ |
1452 | 1532 | ||
1453 | /* If no tape support, then these become defined out of existence */ | 1533 | /* If no tape support, then these become defined out of existence */ |