**
** Supported NCR/SYMBIOS chips:
** 53C720 (Wide, Fast SCSI-2, intfly problems)
-**
-** Other features:
-** Memory mapped IO (linux-1.3.X and above only)
-** Module
-** Shared IRQ (since linux-1.3.72)
*/
/* Name and version of the driver */
#include <asm/io.h>
#include <asm/system.h>
-#include "scsi.h"
-#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
#include "ncr53c8xx.h"
-/*
-** Donnot compile integrity checking code for Linux-2.3.0
-** and above since SCSI data structures are not ready yet.
-*/
-/* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) */
-#if 0
-#define SCSI_NCR_INTEGRITY_CHECKING
-#endif
-
#define NAME53C "ncr53c"
#define NAME53C8XX "ncr53c8xx"
-#define DRIVER_SMP_LOCK ncr53c8xx_lock
#include "sym53c8xx_comm.h"
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))
-static void ncr53c8xx_timeout(unsigned long np);
-static int ncr53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
- int length, int func);
-
#define initverbose (driver_setup.verbose)
#define bootverbose (np->verbose)
#define NS_WIDE (2)
#define NS_PPR (4)
-/*==========================================================
-**
-** "Special features" of targets.
-** quirks field of struct tcb.
-** actualquirks field of struct ccb.
-**
-**==========================================================
-*/
-
-#define QUIRK_AUTOSAVE (0x01)
-#define QUIRK_NOMSG (0x02)
-#define QUIRK_NOSYNC (0x10)
-#define QUIRK_NOWIDE16 (0x20)
-
-/*==========================================================
-**
-** Capability bits in Inquire response byte 7.
-**
-**==========================================================
-*/
-
-#define INQ7_QUEUE (0x02)
-#define INQ7_SYNC (0x10)
-#define INQ7_WIDE16 (0x20)
-
/*==========================================================
**
** Misc.
**==========================================================
*/
+static struct scsi_transport_template *ncr53c8xx_transport_template = NULL;
+
struct tcb;
struct lcb;
struct ccb;
*/
struct link jump_lcb[4]; /* JUMPs for reselection */
struct lcb * lp[MAX_LUN]; /* The lcb's of this tcb */
- u_char inq_done; /* Target capabilities received */
- u_char inq_byte7; /* Contains these capabilities */
/*----------------------------------------------------------------
** Pointer to the ccb used for negotiation.
/*3*/ u_char wval;
#endif
-#ifdef SCSI_NCR_INTEGRITY_CHECKING
- u_char ic_min_sync;
- u_char ic_max_width;
- u_char ic_maximums_set;
- u_char ic_done;
-#endif
-
/* User settable limits and options. */
u_char usrsync;
u_char usrwide;
u_char usrtags;
u_char usrflag;
+ struct scsi_target *starget;
};
/*========================================================================
** CCB queue management.
**----------------------------------------------------------------
*/
- XPT_QUEHEAD free_ccbq; /* Queue of available CCBs */
- XPT_QUEHEAD busy_ccbq; /* Queue of busy CCBs */
- XPT_QUEHEAD wait_ccbq; /* Queue of waiting for IO CCBs */
- XPT_QUEHEAD skip_ccbq; /* Queue of skipped CCBs */
+ struct list_head free_ccbq; /* Queue of available CCBs */
+ struct list_head busy_ccbq; /* Queue of busy CCBs */
+ struct list_head wait_ccbq; /* Queue of waiting for IO CCBs */
+ struct list_head skip_ccbq; /* Queue of skipped CCBs */
u_char actccbs; /* Number of allocated CCBs */
u_char busyccbs; /* CCBs busy for this lun */
u_char queuedccbs; /* CCBs queued to the controller*/
u_char usetags; /* Command queuing is active */
u_char maxtags; /* Max nr of tags asked by user */
u_char numtags; /* Current number of tags */
- u_char inq_byte7; /* Store unit CmdQ capabitility */
/*----------------------------------------------------------------
** QUEUE FULL control and ORDERED tag control.
u_char queued;
u_char auto_sense;
struct ccb * link_ccb; /* Host adapter CCB chain */
- XPT_QUEHEAD link_ccbq; /* Link to unit CCB queue */
+ struct list_head link_ccbq; /* Link to unit CCB queue */
u32 startp; /* Initial data pointer */
u_long magic; /* Free / busy CCB flag */
};
** Virtual and physical bus addresses of the chip.
**----------------------------------------------------------------
*/
- vm_offset_t vaddr; /* Virtual and bus address of */
- vm_offset_t paddr; /* chip's IO registers. */
- vm_offset_t paddr2; /* On-chip RAM bus address. */
+ void __iomem *vaddr; /* Virtual and bus address of */
+ unsigned long paddr; /* chip's IO registers. */
+ unsigned long paddr2; /* On-chip RAM bus address. */
volatile /* Pointer to volatile for */
- struct ncr_reg *reg; /* memory mapped IO. */
+ struct ncr_reg __iomem *reg; /* memory mapped IO. */
/*----------------------------------------------------------------
** SCRIPTS virtual and physical bus addresses.
struct ccb *ccb; /* Global CCB */
struct usrcmd user; /* Command from user */
volatile u_char release_stage; /* Synchronisation stage on release */
-
-#ifdef SCSI_NCR_INTEGRITY_CHECKING
- /*----------------------------------------------------------------
- ** Fields that are used for integrity check
- **----------------------------------------------------------------
- */
- unsigned char check_integrity; /* Enable midlayer integ.check on
- * bus scan. */
- unsigned char check_integ_par; /* Set if par or Init. Det. error
- * used only during integ check */
-#endif
};
#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl))
#endif
ncrcmd save_dp [ 7];
ncrcmd restore_dp [ 5];
- ncrcmd disconnect [ 17];
+ ncrcmd disconnect [ 10];
ncrcmd msg_out [ 9];
ncrcmd msg_out_done [ 7];
ncrcmd idle [ 2];
static void ncr_init_ccb (struct ncb *np, struct ccb *cp);
static void ncr_init_tcb (struct ncb *np, u_char tn);
static struct lcb * ncr_alloc_lcb (struct ncb *np, u_char tn, u_char ln);
-static struct lcb * ncr_setup_lcb (struct ncb *np, u_char tn, u_char ln,
- u_char *inq_data);
+static struct lcb * ncr_setup_lcb (struct ncb *np, struct scsi_device *sdev);
static void ncr_getclock (struct ncb *np, int mult);
static void ncr_selectclock (struct ncb *np, u_char scntl3);
static struct ccb *ncr_get_ccb (struct ncb *np, u_char tn, u_char ln);
static void ncr_int_ma (struct ncb *np);
static void ncr_int_sir (struct ncb *np);
static void ncr_int_sto (struct ncb *np);
-static u_long ncr_lookup (char* id);
static void ncr_negotiate (struct ncb* np, struct tcb* tp);
static int ncr_prepare_nego(struct ncb *np, struct ccb *cp, u_char *msgptr);
-#ifdef SCSI_NCR_INTEGRITY_CHECKING
-static int ncr_ic_nego(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd, u_char *msgptr);
-#endif
static void ncr_script_copy_and_bind
(struct ncb *np, ncrcmd *src, ncrcmd *dst, int len);
static int ncr_scatter (struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd);
static void ncr_getsync (struct ncb *np, u_char sfac, u_char *fakp, u_char *scntl3p);
static void ncr_setsync (struct ncb *np, struct ccb *cp, u_char scntl3, u_char sxfer);
-static void ncr_setup_tags (struct ncb *np, u_char tn, u_char ln);
+static void ncr_setup_tags (struct ncb *np, struct scsi_device *sdev);
static void ncr_setwide (struct ncb *np, struct ccb *cp, u_char wide, u_char ack);
static int ncr_show_msg (u_char * msg);
static void ncr_print_msg (struct ccb *cp, char *label, u_char *msg);
*/
SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
0,
- /*
- ** If QUIRK_AUTOSAVE is set,
- ** do an "save pointer" operation.
- */
- SCR_FROM_REG (QU_REG),
- 0,
- SCR_JUMP ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)),
- PADDR (cleanup_ok),
- /*
- ** like SAVE_DP message:
- ** Copy TEMP register to SAVEP in header.
- */
- SCR_COPY (4),
- RADDR (temp),
- NADDR (header.savep),
SCR_JUMP,
PADDR (cleanup_ok),
*p++ =PADDR (idle);
};
- assert ((u_long)p == (u_long)&scrh->tryloop + sizeof (scrh->tryloop));
+ BUG_ON((u_long)p != (u_long)&scrh->tryloop + sizeof (scrh->tryloop));
#ifdef SCSI_NCR_CCB_DONE_SUPPORT
*p++ =PADDR (done_end);
}
- assert ((u_long)p ==(u_long)&scrh->done_queue+sizeof(scrh->done_queue));
+ BUG_ON((u_long)p != (u_long)&scrh->done_queue+sizeof(scrh->done_queue));
#endif /* SCSI_NCR_CCB_DONE_SUPPORT */
*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
*p++ =offsetof (struct dsb, data[i]);
};
- assert ((u_long)p == (u_long)&scrh->hdata_in + sizeof (scrh->hdata_in));
+
+ BUG_ON((u_long)p != (u_long)&scrh->hdata_in + sizeof (scrh->hdata_in));
p = scr->data_in;
for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
*p++ =offsetof (struct dsb, data[i]);
};
- assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
+
+ BUG_ON((u_long)p != (u_long)&scr->data_in + sizeof (scr->data_in));
p = scrh->hdata_out;
for (i=0; i<MAX_SCATTERH; i++) {
*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
*p++ =offsetof (struct dsb, data[i]);
};
- assert ((u_long)p==(u_long)&scrh->hdata_out + sizeof (scrh->hdata_out));
+
+ BUG_ON((u_long)p != (u_long)&scrh->hdata_out + sizeof (scrh->hdata_out));
p = scr->data_out;
for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
*p++ =offsetof (struct dsb, data[i]);
};
- assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out));
+ BUG_ON((u_long) p != (u_long)&scr->data_out + sizeof (scr->data_out));
}
/*==========================================================
if (opcode == 0) {
printk (KERN_ERR "%s: ERROR0 IN SCRIPT at %d.\n",
ncr_name(np), (int) (src-start-1));
- MDELAY (1000);
+ mdelay(1000);
};
if (DEBUG_FLAGS & DEBUG_SCRIPT)
if ((tmp1 ^ tmp2) & 3) {
printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.\n",
ncr_name(np), (int) (src-start-1));
- MDELAY (1000);
+ mdelay(1000);
}
/*
** If PREFETCH feature not enabled, remove
};
}
-/*==========================================================
-**
-**
-** Auto configuration: attach and init a host adapter.
-**
-**
-**==========================================================
-*/
-
/*
** Linux host data structure
-**
-** The script area is allocated in the host data structure
-** because kmalloc() returns NULL during scsi initialisations
-** with Linux 1.2.X
*/
struct host_data {
}
}
-/*==========================================================
-**
-**
-** Prepare the next negotiation message for integrity check,
-** if needed.
-**
-** Fill in the part of message buffer that contains the
-** negotiation and the nego_status field of the CCB.
-** Returns the size of the message in bytes.
-**
-**
-**==========================================================
-*/
-
-#ifdef SCSI_NCR_INTEGRITY_CHECKING
-static int ncr_ic_nego(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd, u_char *msgptr)
-{
- struct tcb *tp = &np->target[cp->target];
- int msglen = 0;
- int nego = 0;
- u_char no_increase;
-
- if (tp->inq_done) {
-
- if (!tp->ic_maximums_set) {
- tp->ic_maximums_set = 1;
-
- /* check target and host adapter capabilities */
- if ( (tp->inq_byte7 & INQ7_WIDE16) &&
- np->maxwide && tp->usrwide )
- tp->ic_max_width = 1;
- else
- tp->ic_max_width = 0;
-
- if ((tp->inq_byte7 & INQ7_SYNC) && tp->maxoffs) {
- tp->ic_min_sync = (tp->minsync < np->minsync) ?
- np->minsync : tp->minsync;
- }
- else
- tp->ic_min_sync = 255;
-
- tp->period = 1;
- tp->widedone = 1;
- }
-
- if (DEBUG_FLAGS & DEBUG_IC) {
- printk("%s: cmd->ic_nego %d, 1st byte 0x%2X\n",
- ncr_name(np), cmd->ic_nego, cmd->cmnd[0]);
- }
-
- /* First command from integrity check routine will request
- * a PPR message. Disable.
- */
- if ((cmd->ic_nego & NS_PPR) == NS_PPR)
- cmd->ic_nego &= ~NS_PPR;
- /* Previous command recorded a parity or an initiator
- * detected error condition. Force bus to narrow for this
- * target. Clear flag. Negotation on request sense.
- * Note: kernel forces 2 bus resets :o( but clears itself out.
- * Minor bug? in scsi_obsolete.c (ugly)
- */
- if (np->check_integ_par) {
- printk("%s: Parity Error. Target set to narrow.\n",
- ncr_name(np));
- tp->ic_max_width = 0;
- tp->widedone = tp->period = 0;
- }
-
- /* In case of a bus reset, ncr_negotiate will reset
- * the flags tp->widedone and tp->period to 0, forcing
- * a new negotiation.
- */
- no_increase = 0;
- if (tp->widedone == 0) {
- cmd->ic_nego = NS_WIDE;
- tp->widedone = 1;
- no_increase = 1;
- }
- else if (tp->period == 0) {
- cmd->ic_nego = NS_SYNC;
- tp->period = 1;
- no_increase = 1;
- }
-
- switch (cmd->ic_nego) {
- case NS_WIDE:
- /*
- ** negotiate wide transfers ?
- ** Do NOT negotiate if device only supports
- ** narrow.
- */
- if (tp->ic_max_width | np->check_integ_par) {
- nego = NS_WIDE;
-
- msgptr[msglen++] = M_EXTENDED;
- msgptr[msglen++] = 2;
- msgptr[msglen++] = M_X_WIDE_REQ;
- msgptr[msglen++] = cmd->ic_nego_width & tp->ic_max_width;
- }
- else
- cmd->ic_nego_width &= tp->ic_max_width;
-
- break;
-
- case NS_SYNC:
- /*
- ** negotiate synchronous transfers?
- ** Target must support sync transfers.
- **
- ** If period becomes longer than max, reset to async
- */
-
- if (tp->inq_byte7 & INQ7_SYNC) {
-
- nego = NS_SYNC;
-
- msgptr[msglen++] = M_EXTENDED;
- msgptr[msglen++] = 3;
- msgptr[msglen++] = M_X_SYNC_REQ;
-
- switch (cmd->ic_nego_sync) {
- case 2: /* increase the period */
- if (!no_increase) {
- if (tp->ic_min_sync <= 0x0A)
- tp->ic_min_sync = 0x0C;
- else if (tp->ic_min_sync <= 0x0C)
- tp->ic_min_sync = 0x19;
- else if (tp->ic_min_sync <= 0x19)
- tp->ic_min_sync *= 2;
- else {
- tp->ic_min_sync = 255;
- cmd->ic_nego_sync = 0;
- tp->maxoffs = 0;
- }
- }
- msgptr[msglen++] = tp->maxoffs?tp->ic_min_sync:0;
- msgptr[msglen++] = tp->maxoffs;
- break;
-
- case 1: /* nego. to maximum */
- msgptr[msglen++] = tp->maxoffs?tp->ic_min_sync:0;
- msgptr[msglen++] = tp->maxoffs;
- break;
-
- case 0: /* nego to async */
- default:
- msgptr[msglen++] = 0;
- msgptr[msglen++] = 0;
- break;
- };
- }
- else
- cmd->ic_nego_sync = 0;
- break;
-
- case NS_NOCHANGE:
- default:
- break;
- };
- };
-
- cp->nego_status = nego;
- np->check_integ_par = 0;
-
- if (nego) {
- tp->nego_cp = cp;
- if (DEBUG_FLAGS & DEBUG_NEGO) {
- ncr_print_msg(cp, nego == NS_WIDE ?
- "wide/narrow msgout": "sync/async msgout", msgptr);
- };
- };
-
- return msglen;
-}
-#endif /* SCSI_NCR_INTEGRITY_CHECKING */
-
/*==========================================================
**
**
struct tcb *tp = &np->target[cp->target];
int msglen = 0;
int nego = 0;
+ struct scsi_target *starget = tp->starget;
- if (tp->inq_done) {
+ if (likely(starget)) {
/*
** negotiate wide transfers ?
*/
if (!tp->widedone) {
- if (tp->inq_byte7 & INQ7_WIDE16) {
+ if (spi_support_wide(starget)) {
nego = NS_WIDE;
-#ifdef SCSI_NCR_INTEGRITY_CHECKING
- if (tp->ic_done)
- tp->usrwide &= tp->ic_max_width;
-#endif
} else
tp->widedone=1;
*/
if (!nego && !tp->period) {
- if (tp->inq_byte7 & INQ7_SYNC) {
+ if (spi_support_sync(starget)) {
nego = NS_SYNC;
-#ifdef SCSI_NCR_INTEGRITY_CHECKING
- if ((tp->ic_done) &&
- (tp->minsync < tp->ic_min_sync))
- tp->minsync = tp->ic_min_sync;
-#endif
} else {
tp->period =0xffff;
PRINT_TARGET(np, cp->target);
**----------------------------------------------------
*/
- direction = scsi_data_direction(cmd);
- if (direction != SCSI_DATA_NONE) {
+ direction = cmd->sc_data_direction;
+ if (direction != DMA_NONE) {
segments = ncr_scatter(np, cp, cp->cmd);
if (segments < 0) {
ncr_free_ccb(np, cp);
cp->nego_status = 0;
-#ifdef SCSI_NCR_INTEGRITY_CHECKING
- if ((np->check_integrity && tp->ic_done) || !np->check_integrity) {
- if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) {
- msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
- }
- }
- else if (np->check_integrity && (cmd->ic_in_progress)) {
- msglen += ncr_ic_nego (np, cp, cmd, msgptr + msglen);
- }
- else if (np->check_integrity && cmd->ic_complete) {
- /*
- * Midlayer signal to the driver that all of the scsi commands
- * for the integrity check have completed. Save the negotiated
- * parameters (extracted from sval and wval).
- */
-
- {
- u_char idiv;
- idiv = (tp->wval>>4) & 0x07;
- if ((tp->sval&0x1f) && idiv )
- tp->period = (((tp->sval>>5)+4)
- *div_10M[idiv-1])/np->clock_khz;
- else
- tp->period = 0xffff;
- }
- /*
- * tp->period contains 10 times the transfer period,
- * which itself is 4 * the requested negotiation rate.
- */
- if (tp->period <= 250) tp->ic_min_sync = 10;
- else if (tp->period <= 303) tp->ic_min_sync = 11;
- else if (tp->period <= 500) tp->ic_min_sync = 12;
- else
- tp->ic_min_sync = (tp->period + 40 - 1) / 40;
-
-
- /*
- * Negotiation for this target it complete.
- */
- tp->ic_max_width = (tp->wval & EWS) ? 1: 0;
- tp->ic_done = 1;
- tp->widedone = 1;
-
- printk("%s: Integrity Check Complete: \n", ncr_name(np));
-
- printk("%s: %s %s SCSI", ncr_name(np),
- (tp->sval&0x1f)?"SYNC":"ASYNC",
- tp->ic_max_width?"WIDE":"NARROW");
-
- if (tp->sval&0x1f) {
- u_long mbs = 10000 * (tp->ic_max_width + 1);
-
- printk(" %d.%d MB/s", (int) (mbs / tp->period),
- (int) (mbs % tp->period));
-
- printk(" (%d ns, %d offset)\n",
- tp->period/10, tp->sval&0x1f);
- } else {
- printk(" %d MB/s. \n ", (tp->ic_max_width+1)*5);
- }
- }
-#else
if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) {
msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
}
-#endif /* SCSI_NCR_INTEGRITY_CHECKING */
/*----------------------------------------------------
**
**----------------------------------------------------
*/
if (!cp->data_len)
- direction = SCSI_DATA_NONE;
+ direction = DMA_NONE;
/*
- ** If data direction is UNKNOWN, speculate DATA_READ
- ** but prepare alternate pointers for WRITE in case
+ ** If data direction is BIDIRECTIONAL, speculate FROM_DEVICE
+ ** but prepare alternate pointers for TO_DEVICE in case
** of our speculation will be just wrong.
** SCRIPTS will swap values if needed.
*/
switch(direction) {
- case SCSI_DATA_UNKNOWN:
- case SCSI_DATA_WRITE:
+ case DMA_BIDIRECTIONAL:
+ case DMA_TO_DEVICE:
goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
if (segments <= MAX_SCATTERL)
lastp = goalp - 8 - (segments * 16);
lastp = NCB_SCRIPTH_PHYS (np, hdata_out2);
lastp -= (segments - MAX_SCATTERL) * 16;
}
- if (direction != SCSI_DATA_UNKNOWN)
+ if (direction != DMA_BIDIRECTIONAL)
break;
cp->phys.header.wgoalp = cpu_to_scr(goalp);
cp->phys.header.wlastp = cpu_to_scr(lastp);
/* fall through */
- case SCSI_DATA_READ:
+ case DMA_FROM_DEVICE:
goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
if (segments <= MAX_SCATTERL)
lastp = goalp - 8 - (segments * 16);
}
break;
default:
- case SCSI_DATA_NONE:
+ case DMA_NONE:
lastp = goalp = NCB_SCRIPT_PHYS (np, no_data);
break;
}
cp->phys.header.lastp = cpu_to_scr(lastp);
cp->phys.header.goalp = cpu_to_scr(goalp);
- if (direction == SCSI_DATA_UNKNOWN)
+ if (direction == DMA_BIDIRECTIONAL)
cp->phys.header.savep =
cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io));
else
/*
** status
*/
- cp->actualquirks = tp->quirks;
+ cp->actualquirks = 0;
cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
cp->scsi_status = S_ILLEGAL;
cp->parity_status = 0;
static void ncr_start_next_ccb(struct ncb *np, struct lcb *lp, int maxn)
{
- XPT_QUEHEAD *qp;
+ struct list_head *qp;
struct ccb *cp;
if (lp->held_ccb)
return;
while (maxn-- && lp->queuedccbs < lp->queuedepth) {
- qp = xpt_remque_head(&lp->wait_ccbq);
+ qp = ncr_list_pop(&lp->wait_ccbq);
if (!qp)
break;
++lp->queuedccbs;
- cp = xpt_que_entry(qp, struct ccb, link_ccbq);
- xpt_insque_tail(qp, &lp->busy_ccbq);
+ cp = list_entry(qp, struct ccb, link_ccbq);
+ list_add_tail(qp, &lp->busy_ccbq);
lp->jump_ccb[cp->tag == NO_TAG ? 0 : cp->tag] =
cpu_to_scr(CCB_PHYS (cp, restart));
ncr_put_start_queue(np, cp);
ncr_name(np), settle_delay);
ncr_chip_reset(np, 100);
- UDELAY (2000); /* The 895 needs time for the bus mode to settle */
+ udelay(2000); /* The 895 needs time for the bus mode to settle */
if (enab_int)
OUTW (nc_sien, RST);
/*
*/
OUTB (nc_stest3, TE);
OUTB (nc_scntl1, CRST);
- UDELAY (200);
+ udelay(200);
if (!driver_setup.bus_check)
goto out;
return SUCCESS;
}
+#if 0 /* unused and broken.. */
/*==========================================================
**
**
return retv;
}
-
-/*==========================================================
-**
-** Linux release module stuff.
-**
-** Called before unloading the module
-** Detach the host.
-** We have to free resources and halt the NCR chip
-**
-**==========================================================
-*/
+#endif
static void ncr_detach(struct ncb *np)
{
printk("%s: stopping the timer\n", ncr_name(np));
#endif
np->release_stage = 1;
- for (i = 50 ; i && np->release_stage != 2 ; i--) MDELAY (100);
+ for (i = 50 ; i && np->release_stage != 2 ; i--)
+ mdelay(100);
if (np->release_stage != 2)
printk("%s: the timer seems to be already stopped\n", ncr_name(np));
else np->release_stage = 2;
if (lp && lp->held_ccb) {
if (cp == lp->held_ccb) {
- xpt_que_splice(&lp->skip_ccbq, &lp->wait_ccbq);
- xpt_que_init(&lp->skip_ccbq);
+ list_splice_init(&lp->skip_ccbq, &lp->wait_ccbq);
lp->held_ccb = NULL;
}
}
if (!lp)
ncr_alloc_lcb (np, cmd->device->id, cmd->device->lun);
- /*
- ** On standard INQUIRY response (EVPD and CmDt
- ** not set), setup logical unit according to
- ** announced capabilities (we need the 1rst 7 bytes).
- */
- if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) &&
- cmd->cmnd[4] >= 7 && !cmd->use_sg) {
- sync_scsi_data_for_cpu(np, cmd); /* SYNC the data */
- ncr_setup_lcb (np, cmd->device->id, cmd->device->lun,
- (char *) cmd->request_buffer);
- sync_scsi_data_for_device(np, cmd); /* SYNC the data */
- }
-
tp->bytes += cp->data_len;
tp->transfers ++;
if (lp->num_good >= 1000) {
lp->num_good = 0;
++lp->numtags;
- ncr_setup_tags (np, cmd->device->id, cmd->device->lun);
+ ncr_setup_tags (np, cmd->device);
}
}
} else if ((cp->host_status == HS_COMPLETE)
** requeue awaiting scsi commands for this lun.
*/
if (lp && lp->queuedccbs < lp->queuedepth &&
- !xpt_que_empty(&lp->wait_ccbq))
+ !list_empty(&lp->wait_ccbq))
ncr_start_next_ccb(np, lp, 2);
/*
cp->host_status &= ~HS_SKIPMASK;
cp->start.schedule.l_paddr =
cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
- xpt_remque(&cp->link_ccbq);
- xpt_insque_tail(&cp->link_ccbq, &lp->skip_ccbq);
+ list_del(&cp->link_ccbq);
+ list_add_tail(&cp->link_ccbq, &lp->skip_ccbq);
if (cp->queued) {
--lp->queuedccbs;
}
static void ncr_chip_reset(struct ncb *np, int delay)
{
OUTB (nc_istat, SRST);
- UDELAY (delay);
+ udelay(delay);
OUTB (nc_istat, 0 );
if (np->features & FE_EHP)
if (reset) {
OUTB (nc_istat, SRST);
- UDELAY (100);
+ udelay(100);
}
else {
OUTB (nc_stest3, TE|CSF);
if (minsync > np->maxsync)
minsync = 255;
+ if (tp->maxoffs > np->maxoffs)
+ tp->maxoffs = np->maxoffs;
+
tp->minsync = minsync;
- tp->maxoffs = (minsync<255 ? np->maxoffs : 0);
+ tp->maxoffs = (minsync<255 ? tp->maxoffs : 0);
/*
** period=0: has to negotiate sync transfer
static void ncr_setsync (struct ncb *np, struct ccb *cp, u_char scntl3, u_char sxfer)
{
- struct scsi_cmnd *cmd;
+ struct scsi_cmnd *cmd = cp->cmd;
struct tcb *tp;
u_char target = INB (nc_sdid) & 0x0f;
u_char idiv;
- assert (cp && cp->cmd);
- if (!cp) return;
-
- cmd = cp->cmd;
- if (!cmd) return;
-
- assert (target == (cmd->device->id & 0xf));
+ BUG_ON(target != (cmd->device->id & 0xf));
tp = &np->target[target];
static void ncr_setwide (struct ncb *np, struct ccb *cp, u_char wide, u_char ack)
{
- struct scsi_cmnd *cmd;
+ struct scsi_cmnd *cmd = cp->cmd;
u16 target = INB (nc_sdid) & 0x0f;
struct tcb *tp;
u_char scntl3;
u_char sxfer;
- assert (cp && cp->cmd);
- if (!cp) return;
-
- cmd = cp->cmd;
- if (!cmd) return;
-
- assert (target == (cmd->device->id & 0xf));
+ BUG_ON(target != (cmd->device->id & 0xf));
tp = &np->target[target];
tp->widedone = wide+1;
**==========================================================
*/
-static void ncr_setup_tags (struct ncb *np, u_char tn, u_char ln)
+static void ncr_setup_tags (struct ncb *np, struct scsi_device *sdev)
{
+ unsigned char tn = sdev->id, ln = sdev->lun;
struct tcb *tp = &np->target[tn];
struct lcb *lp = tp->lp[ln];
u_char reqtags, maxdepth;
/*
** Just in case ...
*/
- if ((!tp) || (!lp))
+ if ((!tp) || (!lp) || !sdev)
return;
/*
** only devices capable of tagged commands
** only if enabled by user ..
*/
- if ((lp->inq_byte7 & INQ7_QUEUE) && lp->numtags > 1) {
+ if (sdev->tagged_supported && lp->numtags > 1) {
reqtags = lp->numtags;
} else {
reqtags = 1;
}
}
-/*----------------------------------------------------
-**
-** handle user commands
-**
-**----------------------------------------------------
-*/
-
-#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
-
-static void ncr_usercmd (struct ncb *np)
-{
- u_char t;
- struct tcb *tp;
-
- switch (np->user.cmd) {
-
- case 0: return;
-
- case UC_SETSYNC:
- for (t=0; t<MAX_TARGET; t++) {
- if (!((np->user.target>>t)&1)) continue;
- tp = &np->target[t];
- tp->usrsync = np->user.data;
- ncr_negotiate (np, tp);
- };
- break;
-
- case UC_SETTAGS:
- for (t=0; t<MAX_TARGET; t++) {
- int ln;
- if (!((np->user.target>>t)&1)) continue;
- np->target[t].usrtags = np->user.data;
- for (ln = 0; ln < MAX_LUN; ln++) {
- struct lcb *lp = np->target[t].lp[ln];
- if (!lp)
- continue;
- lp->maxtags = lp->numtags = np->user.data;
- ncr_setup_tags (np, t, ln);
- }
- };
- break;
-
- case UC_SETDEBUG:
-#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
- ncr_debug = np->user.data;
-#endif
- break;
-
- case UC_SETORDER:
- np->order = np->user.data;
- break;
-
- case UC_SETVERBOSE:
- np->verbose = np->user.data;
- break;
-
- case UC_SETWIDE:
- for (t=0; t<MAX_TARGET; t++) {
- u_long size;
- if (!((np->user.target>>t)&1)) continue;
- tp = &np->target[t];
- size = np->user.data;
- if (size > np->maxwide) size=np->maxwide;
- tp->usrwide = size;
- ncr_negotiate (np, tp);
- };
- break;
-
- case UC_SETFLAG:
- for (t=0; t<MAX_TARGET; t++) {
- if (!((np->user.target>>t)&1)) continue;
- tp = &np->target[t];
- tp->usrflag = np->user.data;
- };
- break;
- }
- np->user.cmd=0;
-}
-#endif
-
/*==========================================================
**
**
else
msg = M_ID_ERROR;
-#ifdef SCSI_NCR_INTEGRITY_CHECKING
- /*
- ** Save error message. For integrity check use only.
- */
- if (np->check_integrity)
- np->check_integ_par = msg;
-#endif
/*
* If the NCR stopped on a MOVE ^ DATA_IN, we jump to a
struct scsi_cmnd *cmd = cp->cmd;
struct tcb *tp = &np->target[cmd->device->id];
struct lcb *lp = tp->lp[cmd->device->lun];
- XPT_QUEHEAD *qp;
+ struct list_head *qp;
struct ccb * cp2;
int disc_cnt = 0;
int busy_cnt = 0;
** are before cp and busy ones after.
*/
if (lp) {
- qp = lp->busy_ccbq.blink;
+ qp = lp->busy_ccbq.prev;
while (qp != &lp->busy_ccbq) {
- cp2 = xpt_que_entry(qp, struct ccb, link_ccbq);
- qp = qp->blink;
+ cp2 = list_entry(qp, struct ccb, link_ccbq);
+ qp = qp->prev;
++busy_cnt;
if (cp2 == cp)
break;
if (disc_cnt < lp->numtags) {
lp->numtags = disc_cnt > 2 ? disc_cnt : 2;
lp->num_good = 0;
- ncr_setup_tags (np, cmd->device->id, cmd->device->lun);
+ ncr_setup_tags (np, cmd->device);
}
/*
** Requeue the command to the start queue.
/*
** sense data
*/
- bzero(cp->sense_buf, sizeof(cp->sense_buf));
+ memset(cp->sense_buf, 0, sizeof(cp->sense_buf));
cp->phys.sense.addr = cpu_to_scr(CCB_PHYS(cp,sense_buf[0]));
cp->phys.sense.size = cpu_to_scr(sizeof(cp->sense_buf));
/*
** Select without ATN for quirky devices.
*/
- if (tp->quirks & QUIRK_NOMSG)
+ if (cmd->device->select_no_atn)
cp->start.schedule.l_paddr =
cpu_to_scr(NCB_SCRIPTH_PHYS (np, select_no_atn));
u_long dsa = INL (nc_dsa);
u_char target = INB (nc_sdid) & 0x0f;
struct tcb *tp = &np->target[target];
+ struct scsi_target *starget = tp->starget;
if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
while (cp && (CCB_PHYS (cp, phys) != dsa))
cp = cp->link_ccb;
- assert (cp && cp == np->header.cp);
+ BUG_ON(!cp);
+ BUG_ON(cp != np->header.cp);
if (!cp || cp != np->header.cp)
goto out;
case NS_SYNC:
ncr_setsync (np, cp, 0, 0xe0);
+ spi_period(starget) = 0;
+ spi_offset(starget) = 0;
break;
case NS_WIDE:
ncr_setwide (np, cp, 0, 0);
+ spi_width(starget) = 0;
break;
};
** it CAN transfer synch.
*/
- if (ofs)
- tp->inq_byte7 |= INQ7_SYNC;
+ if (ofs && tp->starget)
+ spi_support_sync(tp->starget) = 1;
/*
** check values against driver limits.
** Answer wasn't acceptable.
*/
ncr_setsync (np, cp, 0, 0xe0);
+ spi_period(starget) = 0;
+ spi_offset(starget) = 0;
OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
} else {
/*
** Answer is ok.
*/
ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+ spi_period(starget) = per;
+ spi_offset(starget) = ofs;
OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
};
return;
case NS_WIDE:
ncr_setwide (np, cp, 0, 0);
+ spi_width(starget) = 0;
break;
};
};
*/
ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+ spi_period(starget) = per;
+ spi_offset(starget) = ofs;
np->msgout[0] = M_EXTENDED;
np->msgout[1] = 3;
** it CAN transfer wide.
*/
- if (wide)
- tp->inq_byte7 |= INQ7_WIDE16;
+ if (wide && tp->starget)
+ spi_support_wide(tp->starget) = 1;
/*
** check values against driver limits.
** Answer wasn't acceptable.
*/
ncr_setwide (np, cp, 0, 1);
+ spi_width(starget) = 0;
OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
} else {
/*
** Answer is ok.
*/
ncr_setwide (np, cp, wide, 1);
+ spi_width(starget) = wide;
OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
};
return;
case NS_SYNC:
ncr_setsync (np, cp, 0, 0xe0);
+ spi_period(starget) = 0;
+ spi_offset(starget) = 0;
break;
};
};
*/
ncr_setwide (np, cp, wide, 1);
+ spi_width(starget) = wide;
np->msgout[0] = M_EXTENDED;
np->msgout[1] = 2;
** Lun structure available ?
*/
if (lp) {
- XPT_QUEHEAD *qp;
+ struct list_head *qp;
/*
** Keep from using more tags than we can handle.
*/
/*
** Allocate a new CCB if needed.
*/
- if (xpt_que_empty(&lp->free_ccbq))
+ if (list_empty(&lp->free_ccbq))
ncr_alloc_ccb(np, tn, ln);
- /*
- ** Tune tag mode if asked by user.
- */
- if (lp->queuedepth != lp->numtags) {
- ncr_setup_tags(np, tn, ln);
- }
-
/*
** Look for free CCB
*/
- qp = xpt_remque_head(&lp->free_ccbq);
+ qp = ncr_list_pop(&lp->free_ccbq);
if (qp) {
- cp = xpt_que_entry(qp, struct ccb, link_ccbq);
+ cp = list_entry(qp, struct ccb, link_ccbq);
if (cp->magic) {
PRINT_LUN(np, tn, ln);
printk ("ccb free list corrupted (@%p)\n", cp);
cp = NULL;
- }
- else {
- xpt_insque_tail(qp, &lp->wait_ccbq);
+ } else {
+ list_add_tail(qp, &lp->wait_ccbq);
++lp->busyccbs;
}
}
*/
if (lp) {
- if (cp != np->ccb) {
- xpt_remque(&cp->link_ccbq);
- xpt_insque_head(&cp->link_ccbq, &lp->free_ccbq);
- }
+ if (cp != np->ccb)
+ list_move(&cp->link_ccbq, &lp->free_ccbq);
--lp->busyccbs;
if (cp->queued) {
--lp->queuedccbs;
cp->phys.header.cp = cp;
/*
- ** This allows xpt_remque to work for the default ccb.
+ ** This allows list_del to work for the default ccb.
*/
- xpt_que_init(&cp->link_ccbq);
+ INIT_LIST_HEAD(&cp->link_ccbq);
/*
** Initialyze the start and restart launch script.
*/
lp->actccbs++;
np->actccbs++;
- bzero (cp, sizeof (*cp));
+ memset(cp, 0, sizeof (*cp));
ncr_init_ccb(np, cp);
/*
cp->link_ccb = np->ccb->link_ccb;
np->ccb->link_ccb = cp;
- xpt_insque_head(&cp->link_ccbq, &lp->free_ccbq);
- ncr_setup_tags (np, tn, ln);
+ list_add(&cp->link_ccbq, &lp->free_ccbq);
}
/*==========================================================
** These assert's should be moved at driver initialisations.
*/
#ifdef SCSI_NCR_BIG_ENDIAN
- assert (( (offsetof(struct ncr_reg, nc_sxfer) ^
- offsetof(struct tcb , sval )) &3) == 3);
- assert (( (offsetof(struct ncr_reg, nc_scntl3) ^
- offsetof(struct tcb , wval )) &3) == 3);
+ BUG_ON(((offsetof(struct ncr_reg, nc_sxfer) ^
+ offsetof(struct tcb , sval )) &3) != 3);
+ BUG_ON(((offsetof(struct ncr_reg, nc_scntl3) ^
+ offsetof(struct tcb , wval )) &3) != 3);
#else
- assert (( (offsetof(struct ncr_reg, nc_sxfer) ^
- offsetof(struct tcb , sval )) &3) == 0);
- assert (( (offsetof(struct ncr_reg, nc_scntl3) ^
- offsetof(struct tcb , wval )) &3) == 0);
+ BUG_ON(((offsetof(struct ncr_reg, nc_sxfer) ^
+ offsetof(struct tcb , sval )) &3) != 0);
+ BUG_ON(((offsetof(struct ncr_reg, nc_scntl3) ^
+ offsetof(struct tcb , wval )) &3) != 0);
#endif
}
lp = m_calloc_dma(sizeof(struct lcb), "LCB");
if (!lp)
goto fail;
- bzero(lp, sizeof(*lp));
+ memset(lp, 0, sizeof(*lp));
tp->lp[ln] = lp;
/*
/*
** Initialize the CCB queue headers.
*/
- xpt_que_init(&lp->free_ccbq);
- xpt_que_init(&lp->busy_ccbq);
- xpt_que_init(&lp->wait_ccbq);
- xpt_que_init(&lp->skip_ccbq);
+ INIT_LIST_HEAD(&lp->free_ccbq);
+ INIT_LIST_HEAD(&lp->busy_ccbq);
+ INIT_LIST_HEAD(&lp->wait_ccbq);
+ INIT_LIST_HEAD(&lp->skip_ccbq);
/*
** Set max CCBs to 1 and use the default 1 entry
** will play with CHANGE DEFINITION commands. :-)
**------------------------------------------------------------------------
*/
-static struct lcb *ncr_setup_lcb (struct ncb *np, u_char tn, u_char ln, u_char *inq_data)
+static struct lcb *ncr_setup_lcb (struct ncb *np, struct scsi_device *sdev)
{
+ unsigned char tn = sdev->id, ln = sdev->lun;
struct tcb *tp = &np->target[tn];
struct lcb *lp = tp->lp[ln];
- u_char inq_byte7;
+ struct scsi_target *starget = tp->starget;
/*
** If no lcb, try to allocate it.
goto fail;
/*
- ** Get device quirks from a speciality table.
- */
- tp->quirks = ncr_lookup (inq_data);
- if (tp->quirks && bootverbose) {
- PRINT_LUN(np, tn, ln);
- printk ("quirks=%x.\n", tp->quirks);
- }
-
- /*
- ** Evaluate trustable target/unit capabilities.
- ** We only believe device version >= SCSI-2 that
- ** use appropriate response data format (2).
- ** But it seems that some CCS devices also
- ** support SYNC and I donnot want to frustrate
- ** anybody. ;-)
- */
- inq_byte7 = 0;
- if ((inq_data[2] & 0x7) >= 2 && (inq_data[3] & 0xf) == 2)
- inq_byte7 = inq_data[7];
- else if ((inq_data[2] & 0x7) == 1 && (inq_data[3] & 0xf) == 1)
- inq_byte7 = INQ7_SYNC;
-
- /*
- ** Throw away announced LUN capabilities if we are told
- ** that there is no real device supported by the logical unit.
- */
- if ((inq_data[0] & 0xe0) > 0x20 || (inq_data[0] & 0x1f) == 0x1f)
- inq_byte7 &= (INQ7_SYNC | INQ7_WIDE16);
-
- /*
- ** If user is wanting SYNC, force this feature.
+ ** Prepare negotiation
*/
- if (driver_setup.force_sync_nego)
- inq_byte7 |= INQ7_SYNC;
-
- /*
- ** Prepare negotiation if SIP capabilities have changed.
- */
- tp->inq_done = 1;
- if ((inq_byte7 ^ tp->inq_byte7) & (INQ7_SYNC | INQ7_WIDE16)) {
- tp->inq_byte7 = inq_byte7;
+ if (spi_support_wide(starget) || spi_support_sync(starget))
ncr_negotiate(np, tp);
- }
/*
** If unit supports tagged commands, allocate the
** CCB JUMP table if not yet.
*/
- if ((inq_byte7 & INQ7_QUEUE) && lp->jump_ccb == &lp->jump_ccb_0) {
+ if (sdev->tagged_supported && lp->jump_ccb == &lp->jump_ccb_0) {
int i;
lp->jump_ccb = m_calloc_dma(256, "JUMP_CCB");
if (!lp->jump_ccb) {
lp->cb_tags[i] = i;
lp->maxnxs = MAX_TAGS;
lp->tags_stime = ktime_get(3*HZ);
+ ncr_setup_tags (np, sdev);
}
- /*
- ** Adjust tagged queueing status if needed.
- */
- if ((inq_byte7 ^ lp->inq_byte7) & INQ7_QUEUE) {
- lp->inq_byte7 = inq_byte7;
- lp->numtags = lp->maxtags;
- ncr_setup_tags (np, tn, ln);
- }
fail:
return lp;
return (err);
}
-/*==========================================================
-**
-**
-** Device lookup.
-**
-** @GENSCSI@ should be integrated to scsiconf.c
-**
-**
-**==========================================================
-*/
-
-struct table_entry {
- char * manufacturer;
- char * model;
- char * version;
- u_long info;
-};
-
-static struct table_entry device_tab[] =
-{
-#if 0
- {"", "", "", QUIRK_NOMSG},
-#endif
- {"SONY", "SDT-5000", "3.17", QUIRK_NOMSG},
- {"WangDAT", "Model 2600", "01.7", QUIRK_NOMSG},
- {"WangDAT", "Model 3200", "02.2", QUIRK_NOMSG},
- {"WangDAT", "Model 1300", "02.4", QUIRK_NOMSG},
- {"", "", "", 0} /* catch all: must be last entry. */
-};
-
-static u_long ncr_lookup(char * id)
-{
- struct table_entry * p = device_tab;
- char *d, *r, c;
-
- for (;;p++) {
-
- d = id+8;
- r = p->manufacturer;
- while ((c=*r++)) if (c!=*d++) break;
- if (c) continue;
-
- d = id+16;
- r = p->model;
- while ((c=*r++)) if (c!=*d++) break;
- if (c) continue;
-
- d = id+32;
- r = p->version;
- while ((c=*r++)) if (c!=*d++) break;
- if (c) continue;
-
- return (p->info);
- }
-}
-
/*==========================================================
**
** Determine the ncr's clock frequency.
if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */
int i = 20;
while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
- UDELAY (20);
+ udelay(20);
if (!i)
printk("%s: the chip cannot lock the frequency\n", ncr_name(np));
} else /* Wait 20 micro-seconds for doubler */
- UDELAY (20);
+ udelay(20);
OUTB(nc_stest3, HSC); /* Halt the scsi clock */
OUTB(nc_scntl3, scntl3);
OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */
OUTB (nc_stime1, gen); /* set to nominal delay of 1<<gen * 125us */
while (!(INW(nc_sist) & GEN) && ms++ < 100000) {
for (count = 0; count < 10; count ++)
- UDELAY (100); /* count ms */
+ udelay(100); /* count ms */
}
OUTB (nc_stime1, 0); /* disable general purpose timer */
/*
/*===================== LINUX ENTRY POINTS SECTION ==========================*/
-/*
-** Linux select queue depths function
-*/
-
-int ncr53c8xx_slave_configure(struct scsi_device *device)
+static int ncr53c8xx_slave_configure(struct scsi_device *device)
{
struct Scsi_Host *host = device->host;
- struct ncb *np;
- struct tcb *tp;
- struct lcb *lp;
+ struct ncb *np = ((struct host_data *) host->hostdata)->ncb;
+ struct tcb *tp = &np->target[device->id];
+ struct lcb *lp = tp->lp[device->lun];
int numtags, depth_to_use;
- np = ((struct host_data *) host->hostdata)->ncb;
- tp = &np->target[device->id];
- lp = tp->lp[device->lun];
+ tp->starget = device->sdev_target;
+
+ ncr_setup_lcb(np, device);
/*
** Select queue depth from driver setup.
** Since the queue depth is not tunable under Linux,
** we need to know this value in order not to
** announce stupid things to user.
+ **
+ ** XXX(hch): As of Linux 2.6 it certainly _is_ tunable..
+ ** In fact we just tuned it, or did I miss
+ ** something important? :)
*/
if (lp) {
lp->numtags = lp->maxtags = numtags;
lp->scdev_depth = depth_to_use;
}
- ncr_setup_tags (np, device->id, device->lun);
+ ncr_setup_tags (np, device);
#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
np->unit, device->id, device->lun, depth_to_use);
#endif
+ if (spi_support_sync(device->sdev_target) &&
+ !spi_initial_dv(device->sdev_target))
+ spi_dv_device(device);
return 0;
}
-/*
-** Linux entry point of queuecommand() function
-*/
-
-int ncr53c8xx_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+static int ncr53c8xx_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
{
struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb;
unsigned long flags;
cmd->__data_mapped = 0;
cmd->__data_mapping = 0;
- NCR_LOCK_NCB(np, flags);
+ spin_lock_irqsave(&np->smp_lock, flags);
if ((sts = ncr_queue_command(np, cmd)) != DID_OK) {
cmd->result = ScsiResult(sts, 0);
printk("ncr53c8xx : command successfully queued\n");
#endif
- NCR_UNLOCK_NCB(np, flags);
+ spin_unlock_irqrestore(&np->smp_lock, flags);
if (sts != DID_OK) {
unmap_scsi_data(np, cmd);
done(cmd);
+ sts = 0;
}
return sts;
}
-/*
-** Linux entry point of the interrupt handler.
-** Since linux versions > 1.3.70, we trust the kernel for
-** passing the internal host descriptor as 'dev_id'.
-** Otherwise, we scan the host list and call the interrupt
-** routine for each host that uses this IRQ.
-*/
-
irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
{
unsigned long flags;
if (DEBUG_FLAGS & DEBUG_TINY) printk ("[");
- NCR_LOCK_NCB(np, flags);
+ spin_lock_irqsave(&np->smp_lock, flags);
ncr_exception(np);
done_list = np->done_list;
np->done_list = NULL;
- NCR_UNLOCK_NCB(np, flags);
+ spin_unlock_irqrestore(&np->smp_lock, flags);
if (DEBUG_FLAGS & DEBUG_TINY) printk ("]\n");
- if (done_list) {
- NCR_LOCK_SCSI_DONE(done_list->device->host, flags);
- ncr_flush_done_cmds(done_list);
- NCR_UNLOCK_SCSI_DONE(done_list->device->host, flags);
- }
+ if (done_list)
+ ncr_flush_done_cmds(done_list);
return IRQ_HANDLED;
}
-/*
-** Linux entry point of the timer handler
-*/
-
static void ncr53c8xx_timeout(unsigned long npref)
{
- struct ncb *np = (struct ncb *) npref;
- unsigned long flags;
- struct scsi_cmnd *done_list;
+ struct ncb *np = (struct ncb *) npref;
+ unsigned long flags;
+ struct scsi_cmnd *done_list;
- NCR_LOCK_NCB(np, flags);
- ncr_timeout(np);
- done_list = np->done_list;
- np->done_list = NULL;
- NCR_UNLOCK_NCB(np, flags);
+ spin_lock_irqsave(&np->smp_lock, flags);
+ ncr_timeout(np);
+ done_list = np->done_list;
+ np->done_list = NULL;
+ spin_unlock_irqrestore(&np->smp_lock, flags);
- if (done_list) {
- NCR_LOCK_SCSI_DONE(done_list->device->host, flags);
- ncr_flush_done_cmds(done_list);
- NCR_UNLOCK_SCSI_DONE(done_list->device->host, flags);
- }
+ if (done_list)
+ ncr_flush_done_cmds(done_list);
}
-/*
-** Linux entry point of reset() function
-*/
-
-int ncr53c8xx_bus_reset(struct scsi_cmnd *cmd)
+static int ncr53c8xx_bus_reset(struct scsi_cmnd *cmd)
{
struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb;
int sts;
unsigned long flags;
struct scsi_cmnd *done_list;
- NCR_LOCK_NCB(np, flags);
-
/*
* If the mid-level driver told us reset is synchronous, it seems
* that we must call the done() callback for the involved command,
* before returning SUCCESS.
*/
+ spin_lock_irqsave(&np->smp_lock, flags);
sts = ncr_reset_bus(np, cmd, 1);
done_list = np->done_list;
np->done_list = NULL;
- NCR_UNLOCK_NCB(np, flags);
+ spin_unlock_irqrestore(&np->smp_lock, flags);
ncr_flush_done_cmds(done_list);
return sts;
}
-/*
-** Linux entry point of abort() function
-*/
-
-int ncr53c8xx_abort(struct scsi_cmnd *cmd)
+#if 0 /* unused and broken */
+static int ncr53c8xx_abort(struct scsi_cmnd *cmd)
{
struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb;
int sts;
return sts;
}
+#endif
/*
#undef next_wcmd
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-
-/*=========================================================================
-** Proc file system stuff
-**
-** A read operation returns profile information.
-** A write operation is a control command.
-** The string is parsed in the driver code and the command is passed
-** to the ncr_usercmd() function.
-**=========================================================================
-*/
-
-#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
-
-#define is_digit(c) ((c) >= '0' && (c) <= '9')
-#define digit_to_bin(c) ((c) - '0')
-#define is_space(c) ((c) == ' ' || (c) == '\t')
-
-static int skip_spaces(char *ptr, int len)
+static ssize_t show_ncr53c8xx_revision(struct class_device *dev, char *buf)
{
- int cnt, c;
-
- for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt--);
-
- return (len - cnt);
-}
-
-static int get_int_arg(char *ptr, int len, u_long *pv)
-{
- int cnt, c;
- u_long v;
-
- for (v = 0, cnt = len; cnt > 0 && (c = *ptr++) && is_digit(c); cnt--) {
- v = (v * 10) + digit_to_bin(c);
- }
-
- if (pv)
- *pv = v;
-
- return (len - cnt);
+ struct Scsi_Host *host = class_to_shost(dev);
+ struct host_data *host_data = (struct host_data *)host->hostdata;
+
+ return snprintf(buf, 20, "0x%x\n", host_data->ncb->revision_id);
}
-
-static int is_keyword(char *ptr, int len, char *verb)
-{
- int verb_len = strlen(verb);
-
- if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len))
- return verb_len;
- else
- return 0;
-
-}
-
-#define SKIP_SPACES(min_spaces) \
- if ((arg_len = skip_spaces(ptr, len)) < (min_spaces)) \
- return -EINVAL; \
- ptr += arg_len; len -= arg_len;
-
-#define GET_INT_ARG(v) \
- if (!(arg_len = get_int_arg(ptr, len, &(v)))) \
- return -EINVAL; \
- ptr += arg_len; len -= arg_len;
-
-
-/*
-** Parse a control command
-*/
-
-static int ncr_user_command(struct ncb *np, char *buffer, int length)
-{
- char *ptr = buffer;
- int len = length;
- struct usrcmd *uc = &np->user;
- int arg_len;
- u_long target;
-
- bzero(uc, sizeof(*uc));
-
- if (len > 0 && ptr[len-1] == '\n')
- --len;
-
- if ((arg_len = is_keyword(ptr, len, "setsync")) != 0)
- uc->cmd = UC_SETSYNC;
- else if ((arg_len = is_keyword(ptr, len, "settags")) != 0)
- uc->cmd = UC_SETTAGS;
- else if ((arg_len = is_keyword(ptr, len, "setorder")) != 0)
- uc->cmd = UC_SETORDER;
- else if ((arg_len = is_keyword(ptr, len, "setverbose")) != 0)
- uc->cmd = UC_SETVERBOSE;
- else if ((arg_len = is_keyword(ptr, len, "setwide")) != 0)
- uc->cmd = UC_SETWIDE;
- else if ((arg_len = is_keyword(ptr, len, "setdebug")) != 0)
- uc->cmd = UC_SETDEBUG;
- else if ((arg_len = is_keyword(ptr, len, "setflag")) != 0)
- uc->cmd = UC_SETFLAG;
- else
- arg_len = 0;
-
-#ifdef DEBUG_PROC_INFO
-printk("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd);
-#endif
-
- if (!arg_len)
- return -EINVAL;
- ptr += arg_len; len -= arg_len;
-
- switch(uc->cmd) {
- case UC_SETSYNC:
- case UC_SETTAGS:
- case UC_SETWIDE:
- case UC_SETFLAG:
- SKIP_SPACES(1);
- if ((arg_len = is_keyword(ptr, len, "all")) != 0) {
- ptr += arg_len; len -= arg_len;
- uc->target = ~0;
- } else {
- GET_INT_ARG(target);
- uc->target = (1<<target);
-#ifdef DEBUG_PROC_INFO
-printk("ncr_user_command: target=%ld\n", target);
-#endif
- }
- break;
- }
-
- switch(uc->cmd) {
- case UC_SETVERBOSE:
- case UC_SETSYNC:
- case UC_SETTAGS:
- case UC_SETWIDE:
- SKIP_SPACES(1);
- GET_INT_ARG(uc->data);
-#ifdef DEBUG_PROC_INFO
-printk("ncr_user_command: data=%ld\n", uc->data);
-#endif
- break;
- case UC_SETORDER:
- SKIP_SPACES(1);
- if ((arg_len = is_keyword(ptr, len, "simple")))
- uc->data = M_SIMPLE_TAG;
- else if ((arg_len = is_keyword(ptr, len, "ordered")))
- uc->data = M_ORDERED_TAG;
- else if ((arg_len = is_keyword(ptr, len, "default")))
- uc->data = 0;
- else
- return -EINVAL;
- break;
- case UC_SETDEBUG:
- while (len > 0) {
- SKIP_SPACES(1);
- if ((arg_len = is_keyword(ptr, len, "alloc")))
- uc->data |= DEBUG_ALLOC;
- else if ((arg_len = is_keyword(ptr, len, "phase")))
- uc->data |= DEBUG_PHASE;
- else if ((arg_len = is_keyword(ptr, len, "queue")))
- uc->data |= DEBUG_QUEUE;
- else if ((arg_len = is_keyword(ptr, len, "result")))
- uc->data |= DEBUG_RESULT;
- else if ((arg_len = is_keyword(ptr, len, "scatter")))
- uc->data |= DEBUG_SCATTER;
- else if ((arg_len = is_keyword(ptr, len, "script")))
- uc->data |= DEBUG_SCRIPT;
- else if ((arg_len = is_keyword(ptr, len, "tiny")))
- uc->data |= DEBUG_TINY;
- else if ((arg_len = is_keyword(ptr, len, "timing")))
- uc->data |= DEBUG_TIMING;
- else if ((arg_len = is_keyword(ptr, len, "nego")))
- uc->data |= DEBUG_NEGO;
- else if ((arg_len = is_keyword(ptr, len, "tags")))
- uc->data |= DEBUG_TAGS;
- else
- return -EINVAL;
- ptr += arg_len; len -= arg_len;
- }
-#ifdef DEBUG_PROC_INFO
-printk("ncr_user_command: data=%ld\n", uc->data);
-#endif
- break;
- case UC_SETFLAG:
- while (len > 0) {
- SKIP_SPACES(1);
- if ((arg_len = is_keyword(ptr, len, "trace")))
- uc->data |= UF_TRACE;
- else if ((arg_len = is_keyword(ptr, len, "no_disc")))
- uc->data |= UF_NODISC;
- else
- return -EINVAL;
- ptr += arg_len; len -= arg_len;
- }
- break;
- default:
- break;
- }
-
- if (len)
- return -EINVAL;
- else {
- unsigned long flags;
-
- NCR_LOCK_NCB(np, flags);
- ncr_usercmd (np);
- NCR_UNLOCK_NCB(np, flags);
- }
- return length;
-}
-
-#endif /* SCSI_NCR_USER_COMMAND_SUPPORT */
-
-
-#ifdef SCSI_NCR_USER_INFO_SUPPORT
-/*
-** Copy formatted information into the input buffer.
-*/
-
-static int ncr_host_info(struct ncb *np, char *ptr, off_t offset, int len)
-{
- struct info_str info;
-
- info.buffer = ptr;
- info.length = len;
- info.offset = offset;
- info.pos = 0;
-
- copy_info(&info, " Chip NCR53C720, revision id 0x%x, IRQ %d\n",
- np->revision_id, (int) np->irq);
- copy_info(&info, " Synchronous period factor %d, "
- "max commands per lun %d\n",
- (int) np->minsync, MAX_TAGS);
-
- if (driver_setup.debug || driver_setup.verbose > 1) {
- copy_info(&info, " Debug flags 0x%x, verbosity level %d\n",
- driver_setup.debug, driver_setup.verbose);
- }
-
- return info.pos > info.offset? info.pos - info.offset : 0;
-}
-
-#endif /* SCSI_NCR_USER_INFO_SUPPORT */
-
-/*
-** Entry point of the scsi proc fs of the driver.
-** - func = 0 means read (returns profile data)
-** - func = 1 means write (parse user control command)
-*/
-
-static int ncr53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
- int length, int func)
-{
- struct host_data *host_data;
- struct ncb *ncb = NULL;
- int retv;
-
-#ifdef DEBUG_PROC_INFO
-printk("ncr53c8xx_proc_info: hostno=%d, func=%d\n", host->host_no, func);
-#endif
-
- host_data = (struct host_data *) host->hostdata;
- ncb = host_data->ncb;
-
- if (func) {
-#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
- retv = ncr_user_command(ncb, buffer, length);
-#else
- retv = -EINVAL;
-#endif
- }
- else {
- if (start)
- *start = buffer;
-#ifdef SCSI_NCR_USER_INFO_SUPPORT
- retv = ncr_host_info(ncb, buffer, offset, length);
-#else
- retv = -EINVAL;
-#endif
- }
-
- return retv;
-}
-
-/*=========================================================================
-** End of proc file system stuff
-**=========================================================================
-*/
-#endif
-
+
+static struct class_device_attribute ncr53c8xx_revision_attr = {
+ .attr = { .name = "revision", .mode = S_IRUGO, },
+ .show = show_ncr53c8xx_revision,
+};
+
+static struct class_device_attribute *ncr53c8xx_host_attrs[] = {
+ &ncr53c8xx_revision_attr,
+ NULL
+};
/*==========================================================
**
*/
#ifdef MODULE
char *ncr53c8xx; /* command line passed by insmod */
-MODULE_PARM(ncr53c8xx, "s");
+module_param(ncr53c8xx, charp, 0);
#endif
-int __init ncr53c8xx_setup(char *str)
+static int __init ncr53c8xx_setup(char *str)
{
return sym53c8xx__setup(str);
}
__setup("ncr53c8xx=", ncr53c8xx_setup);
#endif
-/*==========================================================
-**
-** Entry point for info() function
-**
-**==========================================================
-*/
-const char *ncr53c8xx_info (struct Scsi_Host *host)
-{
- return SCSI_NCR_DRIVER_NAME;
-}
-
/*
* Host attach and initialisations.
u_long flags = 0;
int i;
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
- tpnt->proc_info = ncr53c8xx_proc_info,
-#endif
- tpnt->info = ncr53c8xx_info;
+ if (!tpnt->name)
+ tpnt->name = SCSI_NCR_DRIVER_NAME;
+ if (!tpnt->shost_attrs)
+ tpnt->shost_attrs = ncr53c8xx_host_attrs;
+
tpnt->queuecommand = ncr53c8xx_queue_command;
tpnt->slave_configure = ncr53c8xx_slave_configure;
- tpnt->eh_bus_reset_handler = ncr53c8xx_bus_reset;
+ tpnt->eh_bus_reset_handler = ncr53c8xx_bus_reset;
tpnt->can_queue = SCSI_NCR_CAN_QUEUE;
tpnt->this_id = 7;
tpnt->sg_tablesize = SCSI_NCR_SG_TABLESIZE;
np = __m_calloc_dma(device->dev, sizeof(struct ncb), "NCB");
if (!np)
goto attach_error;
- NCR_INIT_LOCK_NCB(np);
+ spin_lock_init(&np->smp_lock);
np->dev = device->dev;
np->p_ncb = vtobus(np);
host_data->ncb = np;
if (device->slot.base_v)
np->vaddr = device->slot.base_v;
else
- np->vaddr = (unsigned long)ioremap(device->slot.base_c, 128);
+ np->vaddr = ioremap(device->slot.base_c, 128);
if (!np->vaddr) {
printk(KERN_ERR
* OUTB OUTW OUTL macros can be used safely.
*/
- np->reg = (struct ncr_reg*) np->vaddr;
+ np->reg = (struct ncr_reg __iomem *)np->vaddr;
/* Do chip dependent initialization. */
ncr_prepare_setting(np);
ncr_name(np));
}
- /* Fill Linux host instance structure */
instance->max_channel = 0;
instance->this_id = np->myaddr;
instance->max_id = np->maxwide ? 16 : 8;
instance->dma_channel = 0;
instance->cmd_per_lun = MAX_TAGS;
instance->can_queue = (MAX_START-4);
+ /* This can happen if you forget to call ncr53c8xx_init from
+ * your module_init */
+ BUG_ON(!ncr53c8xx_transport_template);
+ instance->transportt = ncr53c8xx_transport_template;
scsi_set_device(instance, device->dev);
-#ifdef SCSI_NCR_INTEGRITY_CHECKING
- np->check_integrity = 0;
- instance->check_integrity = 0;
-
-#ifdef SCSI_NCR_ENABLE_INTEGRITY_CHECK
- if ( !(driver_setup.bus_check & 0x04) ) {
- np->check_integrity = 1;
- instance->check_integrity = 1;
- }
-#endif
-#endif
/* Patch script to physical addresses */
ncr_script_fill(&script0, &scripth0);
* Process the reset exception if interrupts are not enabled yet.
* Then enable disconnects.
*/
- NCR_LOCK_NCB(np, flags);
+ spin_lock_irqsave(&np->smp_lock, flags);
if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) {
printk(KERN_ERR "%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!\n", ncr_name(np));
- NCR_UNLOCK_NCB(np, flags);
+ spin_unlock_irqrestore(&np->smp_lock, flags);
goto attach_error;
}
ncr_exception(np);
if (driver_setup.settle_delay > 2) {
printk(KERN_INFO "%s: waiting %d seconds for scsi devices to settle...\n",
ncr_name(np), driver_setup.settle_delay);
- MDELAY (1000 * driver_setup.settle_delay);
+ mdelay(1000 * driver_setup.settle_delay);
}
/* start the timeout daemon */
np->order = M_SIMPLE_TAG;
#endif
- NCR_UNLOCK_NCB(np, flags);
+ spin_unlock_irqrestore(&np->smp_lock, flags);
return instance;
ncr_detach(host_data->ncb);
return 1;
}
+
+static void ncr53c8xx_set_period(struct scsi_target *starget, int period)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ncb *np = ((struct host_data *)shost->hostdata)->ncb;
+ struct tcb *tp = &np->target[starget->id];
+
+ if (period > np->maxsync)
+ period = np->maxsync;
+ else if (period < np->minsync)
+ period = np->minsync;
+
+ tp->usrsync = period;
+
+ ncr_negotiate(np, tp);
+}
+
+static void ncr53c8xx_set_offset(struct scsi_target *starget, int offset)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ncb *np = ((struct host_data *)shost->hostdata)->ncb;
+ struct tcb *tp = &np->target[starget->id];
+
+ if (offset > np->maxoffs)
+ offset = np->maxoffs;
+ else if (offset < 0)
+ offset = 0;
+
+ tp->maxoffs = offset;
+
+ ncr_negotiate(np, tp);
+}
+
+static void ncr53c8xx_set_width(struct scsi_target *starget, int width)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ncb *np = ((struct host_data *)shost->hostdata)->ncb;
+ struct tcb *tp = &np->target[starget->id];
+
+ if (width > np->maxwide)
+ width = np->maxwide;
+ else if (width < 0)
+ width = 0;
+
+ tp->usrwide = width;
+
+ ncr_negotiate(np, tp);
+}
+
+static struct spi_function_template ncr53c8xx_transport_functions = {
+ .set_period = ncr53c8xx_set_period,
+ .show_period = 1,
+ .set_offset = ncr53c8xx_set_offset,
+ .show_offset = 1,
+ .set_width = ncr53c8xx_set_width,
+ .show_width = 1,
+};
+
+int __init ncr53c8xx_init(void)
+{
+ ncr53c8xx_transport_template = spi_attach_transport(&ncr53c8xx_transport_functions);
+ if (!ncr53c8xx_transport_template)
+ return -ENODEV;
+ return 0;
+}
+
+void ncr53c8xx_exit(void)
+{
+ spi_release_transport(ncr53c8xx_transport_template);
+}