// SPDX-License-Identifier: GPL-2.0-or-later /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. * * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr> * Copyright (c) 2003-2005 Matthew Wilcox <matthew@wil.cx> * * This driver is derived from the Linux sym53c8xx driver. * Copyright (C) 1998-2000 Gerard Roudier * * The sym53c8xx driver is derived from the ncr53c8xx driver that had been * a port of the FreeBSD ncr driver to Linux-1.2.13. * * The original ncr driver has been written for 386bsd and FreeBSD by * Wolfgang Stanglmeier <wolf@cologne.de> * Stefan Esser <se@mi.Uni-Koeln.de> * Copyright (C) 1994 Wolfgang Stanglmeier * * Other major contributions: * * NVRAM detection and reading. * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> * *-----------------------------------------------------------------------------
*/ #include <linux/ctype.h> #include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/spinlock.h> #include <scsi/scsi.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi_device.h> #include <scsi/scsi_transport.h>
MODULE_PARM_DESC(cmd_per_lun, "The maximum number of tags to use by default");
MODULE_PARM_DESC(burst, "Maximum burst. 0 to disable, 255 to read from registers");
MODULE_PARM_DESC(led, "Set to 1 to enable LED support");
MODULE_PARM_DESC(diff, "0 for no differential mode, 1 for BIOS, 2 for always, 3 for not GPIO3");
MODULE_PARM_DESC(irqm, "0 for open drain, 1 to leave alone, 2 for totem pole");
MODULE_PARM_DESC(buschk, "0 to not check, 1 for detach on error, 2 for warn on error");
MODULE_PARM_DESC(hostid, "The SCSI ID to use for the host adapters");
MODULE_PARM_DESC(verb, "0 for minimal verbosity, 1 for normal, 2 for excessive");
MODULE_PARM_DESC(debug, "Set bits to enable debugging");
MODULE_PARM_DESC(settle, "Settle delay in seconds. Default 3");
MODULE_PARM_DESC(nvram, "Option currently not used");
MODULE_PARM_DESC(excl, "List ioport addresses here to prevent controllers from being attached");
MODULE_PARM_DESC(safe, "Set other settings to a \"safe mode\"");
MODULE_LICENSE("GPL");
MODULE_VERSION(SYM_VERSION);
MODULE_AUTHOR("Matthew Wilcox ");
MODULE_DESCRIPTION("NCR, Symbios and LSI 8xx and 1010 PCI SCSI adapters");
staticvoid sym2_setup_params(void)
{ char *p = excl_string; int xi = 0;
while (p && (xi < 8)) { char *next_p; int val = (int) simple_strtoul(p, &next_p, 0);
sym_driver_setup.excludes[xi++] = val;
p = next_p;
}
/* * Tell the SCSI layer about a BUS RESET.
*/ void sym_xpt_async_bus_reset(struct sym_hcb *np)
{
printf_notice("%s: SCSI BUS has been reset.\n", sym_name(np));
np->s.settle_time = jiffies + sym_driver_setup.settle_delay * HZ;
np->s.settle_time_valid = 1; if (sym_verbose >= 2)
printf_info("%s: command processing suspended for %d seconds\n",
sym_name(np), sym_driver_setup.settle_delay);
}
/* * Choose the more appropriate CAM status if * the IO encountered an extended error.
*/ staticint sym_xerr_cam_status(int cam_status, int x_status)
{ if (x_status) { if (x_status & XE_PARITY_ERR)
cam_status = DID_PARITY; else
cam_status = DID_ERROR;
} return cam_status;
}
/* * Build CAM result for a failed or auto-sensed IO.
*/ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
{ struct scsi_cmnd *cmd = cp->cmd;
u_int cam_status, scsi_status;
/* * Setup pointers that address the data and start the I/O.
*/ int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
{
u32 lastp, goalp; int dir;
/* * Build the CDB.
*/ if (sym_setup_cdb(np, cmd, cp)) goto out_abort;
/* * No direction means no data.
*/
dir = cmd->sc_data_direction; if (dir != DMA_NONE) {
cp->segments = sym_scatter(np, cp, cmd); if (cp->segments < 0) {
sym_set_cam_status(cmd, DID_ERROR); goto out_abort;
}
/* * No segments means no data.
*/ if (!cp->segments)
dir = DMA_NONE;
} else {
cp->data_len = 0;
cp->segments = 0;
}
/* * Set all pointers values needed by SCRIPTS.
*/
cp->phys.head.lastp = cpu_to_scr(lastp);
cp->phys.head.savep = cpu_to_scr(lastp);
cp->startp = cp->phys.head.savep;
cp->goalp = cpu_to_scr(goalp);
/* * When `#ifed 1', the code below makes the driver * panic on the first attempt to write to a SCSI device. * It is the first test we want to do after a driver * change that does not seem obviously safe. :)
*/ #if 0 switch (cp->cdb_buf[0]) { case 0x0A: case 0x2A: case 0xAA:
panic("XXXXXXXXXXXXX WRITE NOT YET ALLOWED XXXXXXXXXXXXXX\n"); break; default: break;
} #endif
/* * activate this job.
*/
sym_put_start_queue(np, cp); return 0;
/* * If we are resetting the ncr, wait for settle_time before * clearing it. Then command processing will be resumed.
*/ if (np->s.settle_time_valid) { if (time_before_eq(np->s.settle_time, thistime)) { if (sym_verbose >= 2 )
printk("%s: command processing resumed\n",
sym_name(np));
np->s.settle_time_valid = 0;
} return;
}
/* * Nothing to do for now, but that may come.
*/ if (np->s.lasttime + 4*HZ < thistime) {
np->s.lasttime = thistime;
}
#ifdef SYM_CONF_PCIQ_MAY_MISS_COMPLETIONS /* * Some way-broken PCI bridges may lead to * completions being lost when the clearing * of the INTFLY flag by the CPU occurs * concurrently with the chip raising this flag. * If this ever happen, lost completions will * be reaped here.
*/
sym_wakeup_done(np); #endif
}
/* * queuecommand method. Entered with the host adapter lock held and * interrupts disabled.
*/ staticint sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd)
{ struct sym_hcb *np = SYM_SOFTC_PTR(cmd); struct sym_ucmd *ucp = SYM_UCMD_PTR(cmd); int sts = 0;
memset(ucp, 0, sizeof(*ucp));
/* * Shorten our settle_time if needed for * this command not to time out.
*/ if (np->s.settle_time_valid && scsi_cmd_to_rq(cmd)->timeout) { unsignedlong tlimit = jiffies + scsi_cmd_to_rq(cmd)->timeout;
tlimit -= SYM_CONF_TIMER_INTERVAL*2; if (time_after(np->s.settle_time, tlimit)) {
np->s.settle_time = tlimit;
}
}
if (np->s.settle_time_valid) return SCSI_MLQUEUE_HOST_BUSY;
/* * Escalate to host reset if the PCI bus went down
*/ if (pci_channel_offline(pdev)) return SCSI_FAILED;
spin_lock_irq(shost->host_lock); /* This one is queued in some place -> to wait for completion */
FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); if (cp->cmd == cmd) {
cmd_queued = 1; break;
}
}
sts = sym_abort_scsiio(np, cmd, 1); /* On error, restore everything and cross fingers :) */ if (sts)
cmd_queued = 0;
/* We may be in an error condition because the PCI bus * went down. In this case, we need to wait until the * PCI bus is reset, the card is reset, and only then * proceed with the scsi error recovery. There's no * point in hurrying; take a leisurely wait.
*/ #define WAIT_FOR_PCI_RECOVERY 35 if (pci_channel_offline(pdev)) {
init_completion(&eh_done);
spin_lock_irq(shost->host_lock); /* Make sure we didn't race */ if (pci_channel_offline(pdev)) {
BUG_ON(sym_data->io_reset);
sym_data->io_reset = &eh_done;
finished_reset = 0;
}
spin_unlock_irq(shost->host_lock); if (!finished_reset)
finished_reset = wait_for_completion_timeout
(sym_data->io_reset,
WAIT_FOR_PCI_RECOVERY*HZ);
spin_lock_irq(shost->host_lock);
sym_data->io_reset = NULL;
spin_unlock_irq(shost->host_lock);
}
if (finished_reset) {
sym_reset_scsi_bus(np, 0);
sym_start_up(shost, 1);
}
if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN) return -ENXIO;
spin_lock_irqsave(np->s.host->host_lock, flags);
/* * Fail the device init if the device is flagged NOSCAN at BOOT in * the NVRAM. This may speed up boot and maintain coherency with * BIOS device numbering. Clearing the flag allows the user to * rescan skipped devices later. We also return an error for * devices not flagged for SCAN LUNS in the NVRAM since some single * lun devices behave badly when asked for a non zero LUN.
*/
if (tp->usrflags & SYM_SCAN_BOOT_DISABLED) {
tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;
starget_printk(KERN_INFO, sdev->sdev_target, "Scan at boot disabled in NVRAM\n");
error = -ENXIO; goto out;
}
if (tp->usrflags & SYM_SCAN_LUNS_DISABLED) { if (sdev->lun != 0) {
error = -ENXIO; goto out;
}
starget_printk(KERN_INFO, sdev->sdev_target, "Multiple LUNs disabled in NVRAM\n");
}
/* * Linux entry point for device queue sizing.
*/ staticint sym53c8xx_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim)
{ struct sym_hcb *np = sym_get_hcb(sdev->host); struct sym_tcb *tp = &np->target[sdev->id]; struct sym_lcb *lp = sym_lp(tp, sdev->lun); int reqtags, depth_to_use;
/* * Get user flags.
*/
lp->curr_flags = lp->user_flags;
/* * Select queue depth from driver setup. * Do not use more than configured by user. * Use at least 1. * Do not use more than our maximum.
*/
reqtags = sym_driver_setup.max_tag; if (reqtags > tp->usrtags)
reqtags = tp->usrtags; if (!sdev->tagged_supported)
reqtags = 0; if (reqtags > SYM_CONF_MAX_TAG)
reqtags = SYM_CONF_MAX_TAG;
depth_to_use = reqtags ? reqtags : 1;
scsi_change_queue_depth(sdev, depth_to_use);
lp->s.scdev_depth = depth_to_use;
sym_tune_dev_queuing(tp, sdev->lun, reqtags);
if (!spi_initial_dv(sdev->sdev_target))
spi_dv_device(sdev);
/* if sdev_init returned before allocating a sym_lcb, return */ if (!lp) return;
spin_lock_irqsave(np->s.host->host_lock, flags);
if (lp->busy_itlq || lp->busy_itl) { /* * This really shouldn't happen, but we can't return an error * so let's try to stop all on-going I/O.
*/
starget_printk(KERN_WARNING, tp->starget, "Removing busy LCB (%d)\n", (u8)sdev->lun);
sym_reset_scsi_bus(np, 1);
}
if (sym_free_lcb(np, sdev->id, sdev->lun) == 0) { /* * It was the last unit for this target.
*/
tp->head.sval = 0;
tp->head.wval = np->rv_scntl3;
tp->head.uval = 0;
tp->tgoal.check_nego = 1;
tp->starget = NULL;
}
/* * Linux entry point for info() function
*/ staticconstchar *sym53c8xx_info (struct Scsi_Host *host)
{ return SYM_DRIVER_NAME;
}
#ifdef SYM_LINUX_PROC_INFO_SUPPORT /* * Proc file system stuff * * A read operation returns adapter information. * A write operation is a control command. * The string is parsed in the driver code and the command is passed * to the sym_usercmd() function.
*/
#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT case UC_SETDEBUG:
sym_debug_flags = uc->data; break; #endif case UC_SETVERBOSE:
np->verbose = uc->data; break; default: /* * We assume that other commands apply to targets. * This should always be the case and avoid the below * 4 lines to be repeated 6 times.
*/ for (t = 0; t < SYM_CONF_MAX_TARGET; t++) { if (!((uc->target >> t) & 1)) continue;
tp = &np->target[t]; if (!tp->nlcb) continue;
/* * Free resources claimed by sym_iomap_device(). Note that * sym_free_resources() should be used instead of this function after calling * sym_attach().
*/ staticvoid sym_iounmap_device(struct sym_device *device)
{ if (device->s.ioaddr)
pci_iounmap(device->pdev, device->s.ioaddr); if (device->s.ramaddr)
pci_iounmap(device->pdev, device->s.ramaddr);
}
/* * Free controller resources.
*/ staticvoid sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev, int do_free_irq)
{ /* * Free O/S specific resources.
*/ if (do_free_irq)
free_irq(pdev->irq, np->s.host); if (np->s.ioaddr)
pci_iounmap(pdev, np->s.ioaddr); if (np->s.ramaddr)
pci_iounmap(pdev, np->s.ramaddr); /* * Free O/S independent resources.
*/
sym_hcb_free(np);
sym_mfree_dma(np, sizeof(*np), "HCB");
}
/* * Host attach and initialisations. * * Allocate host data and ncb structure. * Remap MMIO region. * Do chip initialization. * If all is OK, install interrupt handling and * start the timer daemon.
*/ staticstruct Scsi_Host *sym_attach(conststruct scsi_host_template *tpnt, int unit, struct sym_device *dev)
{ struct sym_data *sym_data; struct sym_hcb *np = NULL; struct Scsi_Host *shost = NULL; struct pci_dev *pdev = dev->pdev; unsignedlong flags; struct sym_fw *fw; int do_free_irq = 0;
printk(KERN_INFO "sym%d: <%s> rev 0x%x at pci %s irq %u\n",
unit, dev->chip.name, pdev->revision, pci_name(pdev),
pdev->irq);
/* * Get the firmware for this chip.
*/
fw = sym_find_firmware(&dev->chip); if (!fw) goto attach_failed;
/* * Allocate immediately the host control block, * since we are only expecting to succeed. :) * We keep track in the HCB of all the resources that * are to be released on error.
*/
np = __sym_calloc_dma(&pdev->dev, sizeof(*np), "HCB"); if (!np) goto attach_failed;
np->bus_dmat = &pdev->dev; /* Result in 1 DMA pool per HBA */
sym_data->ncb = np;
sym_data->pdev = pdev;
np->s.host = shost;
if (sym_hcb_attach(shost, fw, dev->nvram)) goto attach_failed;
/* * Install the interrupt handler. * If we synchonize the C code with SCRIPTS on interrupt, * we do not want to share the INTR line at all.
*/ if (request_irq(pdev->irq, sym53c8xx_intr, IRQF_SHARED, NAME53C8XX,
shost)) {
printf_err("%s: request irq %u failure\n",
sym_name(np), pdev->irq); goto attach_failed;
}
do_free_irq = 1;
/* * After SCSI devices have been opened, we cannot * reset the bus safely, so we do it here.
*/
spin_lock_irqsave(shost->host_lock, flags); if (sym_reset_scsi_bus(np, 0)) goto reset_failed;
/* * Start the SCRIPTS.
*/
sym_start_up(shost, 1);
/* * If user excluded this chip, do not initialize it. * I hate this code so much. Must kill it.
*/ if (io_port) { for (i = 0 ; i < 8 ; i++) { if (sym_driver_setup.excludes[i] == io_port) return -ENODEV;
}
}
/* * Check if the chip is supported. Then copy the chip description * to our device structure so we can make it match the actual device * and options.
*/
chip = sym_lookup_chip_table(pdev->device, pdev->revision); if (!chip) {
dev_info(&pdev->dev, "device not supported\n"); return -ENODEV;
}
memcpy(&device->chip, chip, sizeof(device->chip));
return 0;
}
/* * Ignore Symbios chips controlled by various RAID controllers. * These controllers set value 0x52414944 at RAM end - 16.
*/ staticint sym_check_raid(struct sym_device *device)
{ unsignedint ram_size, ram_val;
/* * (ITEM 12 of a DEL about the 896 I haven't yet). * We must ensure the chip will use WRITE AND INVALIDATE. * The revision number limit is for now arbitrary.
*/ if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && pdev->revision < 0x4) {
chip->features |= (FE_WRIE | FE_CLSE);
}
/* If the chip can do Memory Write Invalidate, enable it */ if (chip->features & FE_WRIE) { if (pci_set_mwi(pdev)) return -ENODEV;
}
/* * Work around for errant bit in 895A. The 66Mhz * capable bit is set erroneously. Clear this bit. * (Item 1 DEL 533) * * Make sure Config space and Features agree. * * Recall: writes are not normal to status register - * write a 1 to clear and a 0 to leave unchanged. * Can only reset bits.
*/
pci_read_config_word(pdev, PCI_STATUS, &status_reg); if (chip->features & FE_66MHZ) { if (!(status_reg & PCI_STATUS_66MHZ))
chip->features &= ~FE_66MHZ;
} else { if (status_reg & PCI_STATUS_66MHZ) {
status_reg = PCI_STATUS_66MHZ;
pci_write_config_word(pdev, PCI_STATUS, status_reg);
pci_read_config_word(pdev, PCI_STATUS, &status_reg);
}
}
return 0;
}
/* * Map HBA registers and on-chip SRAM (if present).
*/ staticint sym_iomap_device(struct sym_device *device)
{ struct pci_dev *pdev = device->pdev; struct pci_bus_region bus_addr; int i = 2;
if (device->chip.features & FE_RAM) { /* * If the BAR is 64-bit, resource 2 will be occupied by the * upper 32 bits
*/ if (!pdev->resource[i].flags)
i++;
pcibios_resource_to_bus(pdev->bus, &bus_addr,
&pdev->resource[i]);
device->ram_base = bus_addr.start;
}
#ifdef CONFIG_SCSI_SYM53C8XX_MMIO if (device->mmio_base)
device->s.ioaddr = pci_iomap(pdev, 1,
pci_resource_len(pdev, 1)); #endif if (!device->s.ioaddr)
device->s.ioaddr = pci_iomap(pdev, 0,
pci_resource_len(pdev, 0)); if (!device->s.ioaddr) {
dev_err(&pdev->dev, "could not map registers; giving up.\n"); return -EIO;
} if (device->ram_base) {
device->s.ramaddr = pci_iomap(pdev, i,
pci_resource_len(pdev, i)); if (!device->s.ramaddr) {
dev_warn(&pdev->dev, "could not map SRAM; continuing anyway.\n");
device->ram_base = 0;
}
}
return 0;
}
/* * The NCR PQS and PDS cards are constructed as a DEC bridge * behind which sits a proprietary NCR memory controller and * either four or two 53c875s as separate devices. We can tell * if an 875 is part of a PQS/PDS or not since if it is, it will * be on the same bus as the memory controller. In its usual * mode of operation, the 875s are slaved to the memory * controller for all transfers. To operate with the Linux * driver, the memory controller is disabled and the 875s * freed to function independently. The only wrinkle is that * the preset SCSI ID (which may be zero) must be read in from * a special configuration space register of the 875.
*/ staticvoid sym_config_pqs(struct pci_dev *pdev, struct sym_device *sym_dev)
{ int slot;
u8 tmp;
/* * Called before unloading the module. * Detach the host. * We have to free resources and halt the NCR chip.
*/ staticint sym_detach(struct Scsi_Host *shost, struct pci_dev *pdev)
{ struct sym_hcb *np = sym_get_hcb(shost);
printk("%s: detaching ...\n", sym_name(np));
timer_delete_sync(&np->s.timer);
/* * Reset NCR chip. * We should use sym_soft_reset(), but we don't want to do * so, since we may not be safe if interrupts occur.
*/
printk("%s: resetting chip\n", sym_name(np));
OUTB(np, nc_istat, SRST);
INB(np, nc_mbox1);
udelay(10);
OUTB(np, nc_istat, 0);
/** * sym2_io_error_detected() - called when PCI error is detected * @pdev: pointer to PCI device * @state: current state of the PCI slot
*/ static pci_ers_result_t sym2_io_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{ /* If slot is permanently frozen, turn everything off */ if (state == pci_channel_io_perm_failure) {
sym2_remove(pdev); return PCI_ERS_RESULT_DISCONNECT;
}
disable_irq(pdev->irq);
pci_disable_device(pdev);
/* Request that MMIO be enabled, so register dump can be taken. */ return PCI_ERS_RESULT_CAN_RECOVER;
}
/* Request a slot reset. */ return PCI_ERS_RESULT_NEED_RESET;
}
/** * sym2_reset_workarounds - hardware-specific work-arounds * @pdev: pointer to PCI device * * This routine is similar to sym_set_workarounds(), except * that, at this point, we already know that the device was * successfully initialized at least once before, and so most * of the steps taken there are un-needed here.
*/ staticvoid sym2_reset_workarounds(struct pci_dev *pdev)
{
u_short status_reg; struct sym_chip *chip;
/* Work around for errant bit in 895A, in a fashion * similar to what is done in sym_set_workarounds().
*/
pci_read_config_word(pdev, PCI_STATUS, &status_reg); if (!(chip->features & FE_66MHZ) && (status_reg & PCI_STATUS_66MHZ)) {
status_reg = PCI_STATUS_66MHZ;
pci_write_config_word(pdev, PCI_STATUS, status_reg);
pci_read_config_word(pdev, PCI_STATUS, &status_reg);
}
}
/** * sym2_io_slot_reset() - called when the pci bus has been reset. * @pdev: pointer to PCI device * * Restart the card from scratch.
*/ static pci_ers_result_t sym2_io_slot_reset(struct pci_dev *pdev)
{ struct Scsi_Host *shost = pci_get_drvdata(pdev); struct sym_hcb *np = sym_get_hcb(shost);
printk(KERN_INFO "%s: recovering from a PCI slot reset\n",
sym_name(np));
if (pci_enable_device(pdev)) {
printk(KERN_ERR "%s: Unable to enable after PCI reset\n",
sym_name(np)); return PCI_ERS_RESULT_DISCONNECT;
}
pci_set_master(pdev);
enable_irq(pdev->irq);
/* If the chip can do Memory Write Invalidate, enable it */ if (np->features & FE_WRIE) { if (pci_set_mwi(pdev)) return PCI_ERS_RESULT_DISCONNECT;
}
/* Perform work-arounds, analogous to sym_set_workarounds() */
sym2_reset_workarounds(pdev);
/* Perform host reset only on one instance of the card */ if (PCI_FUNC(pdev->devfn) == 0) { if (sym_reset_scsi_bus(np, 0)) {
printk(KERN_ERR "%s: Unable to reset scsi host\n",
sym_name(np)); return PCI_ERS_RESULT_DISCONNECT;
}
sym_start_up(shost, 1);
}
return PCI_ERS_RESULT_RECOVERED;
}
/** * sym2_io_resume() - resume normal ops after PCI reset * @pdev: pointer to PCI device * * Called when the error recovery driver tells us that its * OK to resume normal operation. Use completion to allow * halted scsi ops to resume.
*/ staticvoid sym2_io_resume(struct pci_dev *pdev)
{ struct Scsi_Host *shost = pci_get_drvdata(pdev); struct sym_data *sym_data = shost_priv(shost);
spin_lock_irq(shost->host_lock); if (sym_data->io_reset)
complete(sym_data->io_reset);
spin_unlock_irq(shost->host_lock);
}
switch (np->scsi_mode) { case SMODE_SE:
type = SPI_SIGNAL_SE; break; case SMODE_LVD:
type = SPI_SIGNAL_LVD; break; case SMODE_HVD:
type = SPI_SIGNAL_HVD; break; default:
type = SPI_SIGNAL_UNKNOWN; break;
}
spi_signalling(shost) = type;
}
/* have to have DT for these transfers, but DT will also
* set width, so check that this is allowed */ if (period <= np->minsync && spi_width(starget))
tp->tgoal.dt = 1;
/* It is illegal to have DT set on narrow transfers. If DT is
* clear, we must also clear IU and QAS. */ if (width == 0)
tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;
/* We must clear QAS and IU if DT is clear */ if (dt)
tp->tgoal.dt = 1; else
tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;
tp->tgoal.check_nego = 1;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.