aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/cciss.c188
-rw-r--r--drivers/block/cciss.h11
-rw-r--r--drivers/block/cciss_scsi.c82
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[] = {
148static ctlr_info_t *hba[MAX_CTLR]; 148static ctlr_info_t *hba[MAX_CTLR];
149 149
150static void do_cciss_request(request_queue_t *q); 150static void do_cciss_request(request_queue_t *q);
151static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs);
151static int cciss_open(struct inode *inode, struct file *filep); 152static int cciss_open(struct inode *inode, struct file *filep);
152static int cciss_release(struct inode *inode, struct file *filep); 153static int cciss_release(struct inode *inode, struct file *filep);
153static int cciss_ioctl(struct inode *inode, struct file *filep, 154static 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
1895static 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
2011cleanup1: 2089cleanup1:
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
2424static 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
2444static 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
2454static 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
2341static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) 2466static 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
3036clean4: 3165clean4:
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
49struct sendcmd_reject_list {
50 int ncompletions;
51 unsigned long *complete; /* array of NR_CMDS tags */
52};
53
54#endif
47struct ctlr_info 55struct 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... */
46static int sendcmd( 49static int sendcmd(
47 __u8 cmd, 50 __u8 cmd,
@@ -67,6 +70,8 @@ static int cciss_scsi_proc_info(
67 70
68static int cciss_scsi_queue_command (struct scsi_cmnd *cmd, 71static int cciss_scsi_queue_command (struct scsi_cmnd *cmd,
69 void (* done)(struct scsi_cmnd *)); 72 void (* done)(struct scsi_cmnd *));
73static int cciss_eh_device_reset_handler(struct scsi_cmnd *);
74static int cciss_eh_abort_handler(struct scsi_cmnd *);
70 75
71static struct cciss_scsi_hba_t ccissscsi[MAX_CTLR] = { 76static 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
251static int xmargin=8; 259static int xmargin=8;
252static int amargin=60; 260static 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
1470static 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
1501static 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 */