Пример #1
0
void
ahd_setup_data(struct ahd_softc *ahd, struct scsi_xfer *xs,
               struct scb *scb)
{
    struct hardware_scb *hscb;
    int s;

    hscb = scb->hscb;
    xs->resid = xs->status = 0;
    xs->error = CAM_REQ_INPROG;

    hscb->cdb_len = xs->cmdlen;
    if (hscb->cdb_len > MAX_CDB_LEN) {
        ahd_lock(ahd, &s);
        ahd_free_scb(ahd, scb);
        xs->error = XS_DRIVER_STUFFUP;
        scsi_done(xs);
        ahd_unlock(ahd, &s);
        return;
    }

    memcpy(hscb->shared_data.idata.cdb, xs->cmd, hscb->cdb_len);

    /* Only use S/G if there is a transfer */
    if (xs->datalen) {
        int error;

        error = bus_dmamap_load(ahd->parent_dmat,
                                scb->dmamap, xs->data,
                                xs->datalen, NULL,
                                ((xs->flags & SCSI_NOSLEEP) ?
                                 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
                                BUS_DMA_STREAMING |
                                ((xs->flags & XS_CTL_DATA_IN) ?
                                 BUS_DMA_READ : BUS_DMA_WRITE));
        if (error) {
#ifdef AHD_DEBUG
            printf("%s: in ahd_setup_data(): bus_dmamap_load() "
                   "= %d\n", ahd_name(ahd), error);
#endif
            ahd_lock(ahd, &s);
            ahd_free_scb(ahd, scb);
            xs->error = XS_DRIVER_STUFFUP;
            scsi_done(xs);
            ahd_unlock(ahd, &s);
            return;
        }
        ahd_execute_scb(scb, scb->dmamap->dm_segs,
                        scb->dmamap->dm_nsegs);
    } else {
        ahd_execute_scb(scb, NULL, 0);
    }
}
Пример #2
0
static void
ahd_linux_pci_dev_remove(struct pci_dev *pdev)
{
	struct ahd_softc *ahd = pci_get_drvdata(pdev);
	u_long s;

	if (ahd->platform_data && ahd->platform_data->host)
			scsi_remove_host(ahd->platform_data->host);

	ahd_lock(ahd, &s);
	ahd_intr_enable(ahd, FALSE);
	ahd_unlock(ahd, &s);
	ahd_free(ahd);
}
Пример #3
0
void
aic_platform_scb_free(struct ahd_softc *ahd, struct scb *scb)
{
    int s;

    ahd_lock(ahd, &s);

    if ((ahd->flags & AHD_RESOURCE_SHORTAGE) != 0) {
        ahd->flags &= ~AHD_RESOURCE_SHORTAGE;
    }

    if (!cold) {
        /* we are no longer in autoconf */
        timeout_del(&scb->xs->stimeout);
    }

    ahd_unlock(ahd, &s);
}
Пример #4
0
/*
 * Attach all the sub-devices we can find
 */
int
ahd_attach(struct ahd_softc *ahd)
{
    struct scsibus_attach_args saa;
    char   ahd_info[256];
    int	s;

    ahd_controller_info(ahd, ahd_info, sizeof ahd_info);
    printf("%s\n", ahd_info);
    ahd_lock(ahd, &s);

    /*
     * fill in the prototype scsi_links.
     */
    ahd->sc_channel.adapter_target = ahd->our_id;
    if (ahd->features & AHD_WIDE)
        ahd->sc_channel.adapter_buswidth = 16;
    ahd->sc_channel.adapter_softc = ahd;
    ahd->sc_channel.adapter = &ahd_switch;
    ahd->sc_channel.openings = 16;

    if (bootverbose) {
        ahd_controller_info(ahd, ahd_info, sizeof ahd_info);
        printf("%s: %s\n", ahd->sc_dev.dv_xname, ahd_info);
    }

    ahd_intr_enable(ahd, TRUE);

    if (ahd->flags & AHD_RESET_BUS_A)
        ahd_reset_channel(ahd, 'A', TRUE);

    bzero(&saa, sizeof(saa));
    saa.saa_sc_link = &ahd->sc_channel;

    ahd->sc_child = config_found((void *)&ahd->sc_dev, &saa, scsiprint);

    ahd_unlock(ahd, &s);

    return (1);

}
static int
ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length)
{
	ahd_mode_state saved_modes;
	int have_seeprom;
	u_long s;
	int paused;
	int written;

	/* Default to failure. */
	written = -EINVAL;
	ahd_lock(ahd, &s);
	paused = ahd_is_paused(ahd);
	if (!paused)
		ahd_pause(ahd);

	saved_modes = ahd_save_modes(ahd);
	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
	if (length != sizeof(struct seeprom_config)) {
<<<<<<< HEAD
		printk("ahd_proc_write_seeprom: incorrect buffer size\n");
=======
Пример #6
0
static int
ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length)
{
	ahd_mode_state saved_modes;
	int have_seeprom;
	u_long s;
	int paused;
	int written;

	/* Default to failure. */
	written = -EINVAL;
	ahd_lock(ahd, &s);
	paused = ahd_is_paused(ahd);
	if (!paused)
		ahd_pause(ahd);

	saved_modes = ahd_save_modes(ahd);
	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
	if (length != sizeof(struct seeprom_config)) {
		printf("ahd_proc_write_seeprom: incorrect buffer size\n");
		goto done;
	}

	have_seeprom = ahd_verify_cksum((struct seeprom_config*)buffer);
	if (have_seeprom == 0) {
		printf("ahd_proc_write_seeprom: cksum verification failed\n");
		goto done;
	}

	have_seeprom = ahd_acquire_seeprom(ahd);
	if (!have_seeprom) {
		printf("ahd_proc_write_seeprom: No Serial EEPROM\n");
		goto done;
	} else {
		u_int start_addr;

		if (ahd->seep_config == NULL) {
			ahd->seep_config = malloc(sizeof(*ahd->seep_config),
						  M_DEVBUF, M_NOWAIT);
			if (ahd->seep_config == NULL) {
				printf("aic79xx: Unable to allocate serial "
				       "eeprom buffer.  Write failing\n");
				goto done;
			}
		}
		printf("aic79xx: Writing Serial EEPROM\n");
		start_addr = 32 * (ahd->channel - 'A');
		ahd_write_seeprom(ahd, (u_int16_t *)buffer, start_addr,
				  sizeof(struct seeprom_config)/2);
		ahd_read_seeprom(ahd, (uint16_t *)ahd->seep_config,
				 start_addr, sizeof(struct seeprom_config)/2,
				 /*ByteStream*/FALSE);
		ahd_release_seeprom(ahd);
		written = length;
	}

done:
	ahd_restore_modes(ahd, saved_modes);
	if (!paused)
		ahd_unpause(ahd);
	ahd_unlock(ahd, &s);
	return (written);
}
Пример #7
0
int
ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
{
	struct scb_data *shared_scb_data;
	u_int		 command;
	uint32_t	 devconfig;
	uint16_t	 device; 
	uint16_t	 subvendor; 
	int		 error;

	shared_scb_data = NULL;
	ahd->description = entry->name;
	/*
	 * Record if this is a HostRAID board.
	 */
	device = aic_pci_read_config(ahd->dev_softc,
				     PCIR_DEVICE, /*bytes*/2);
	if (DEVID_9005_HOSTRAID(device))
		ahd->flags |= AHD_HOSTRAID_BOARD;

	/*
	 * Record if this is an HP board.
	 */
	subvendor = aic_pci_read_config(ahd->dev_softc,
					PCIR_SUBVEND_0, /*bytes*/2);
	if (subvendor == SUBID_HP)
		ahd->flags |= AHD_HP_BOARD;

	error = entry->setup(ahd);
	if (error != 0)
		return (error);

	/*
	 * Find the PCI-X cap pointer.  If we don't find it,
	 * pcix_ptr will be 0.
	 */
	pci_find_cap(ahd->dev_softc, PCIY_PCIX, &ahd->pcix_ptr);
	devconfig = aic_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4);
	if ((devconfig & PCIXINITPAT) == PCIXINIT_PCI33_66) {
		ahd->chip |= AHD_PCI;
		/* Disable PCIX workarounds when running in PCI mode. */
		ahd->bugs &= ~AHD_PCIX_BUG_MASK;
	} else {
		ahd->chip |= AHD_PCIX;
		if (ahd->pcix_ptr == 0)
			return (ENXIO);
	}
	ahd->bus_description = pci_bus_modes[PCI_BUS_MODES_INDEX(devconfig)];

	aic_power_state_change(ahd, AIC_POWER_STATE_D0);

	error = ahd_pci_map_registers(ahd);
	if (error != 0)
		return (error);

	/*
	 * If we need to support high memory, enable dual
	 * address cycles.  This bit must be set to enable
	 * high address bit generation even if we are on a
	 * 64bit bus (PCI64BIT set in devconfig).
	 */
	if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) {
		uint32_t devconfig;

		if (bootverbose)
			printf("%s: Enabling 39Bit Addressing\n",
			       ahd_name(ahd));
		devconfig = aic_pci_read_config(ahd->dev_softc,
						DEVCONFIG, /*bytes*/4);
		devconfig |= DACEN;
		aic_pci_write_config(ahd->dev_softc, DEVCONFIG,
				     devconfig, /*bytes*/4);
	}
	
	/* Ensure busmastering is enabled */
	command = aic_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2);
	command |= PCIM_CMD_BUSMASTEREN;
	aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/2);

	error = ahd_softc_init(ahd);
	if (error != 0)
		return (error);

	ahd->bus_intr = ahd_pci_intr;

	error = ahd_reset(ahd, /*reinit*/FALSE);
	if (error != 0)
		return (ENXIO);

	ahd->pci_cachesize =
	    aic_pci_read_config(ahd->dev_softc, CSIZE_LATTIME,
				/*bytes*/1) & CACHESIZE;
	ahd->pci_cachesize *= 4;

	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
	/* See if we have a SEEPROM and perform auto-term */
	error = ahd_check_extport(ahd);
	if (error != 0)
		return (error);

	/* Core initialization */
	error = ahd_init(ahd);
	if (error != 0)
		return (error);

	/*
	 * Allow interrupts now that we are completely setup.
	 */
	error = ahd_pci_map_int(ahd);
	if (error != 0)
		return (error);

	ahd_lock(ahd);
	/*
	 * Link this softc in with all other ahd instances.
	 */
	ahd_softc_insert(ahd);
	ahd_unlock(ahd);
	return (0);
}
Пример #8
0
void
ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments)
{
    struct	scb *scb;
    struct	scsi_xfer *xs;
    struct	ahd_softc *ahd;
    struct	ahd_initiator_tinfo *tinfo;
    struct	ahd_tmode_tstate *tstate;
    u_int	mask;
    int	s;

    scb = (struct scb *)arg;
    xs = scb->xs;
    xs->error = CAM_REQ_INPROG;
    xs->status = 0;
    ahd = (struct ahd_softc *)xs->sc_link->adapter_softc;

    if (nsegments != 0) {
        void *sg;
        int op;
        u_int i;

        ahd_setup_data_scb(ahd, scb);

        /* Copy the segments into our SG list */
        for (i = nsegments, sg = scb->sg_list; i > 0; i--) {

            sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr,
                              dm_segs->ds_len,
                              /*last*/i == 1);
            dm_segs++;
        }

        if ((xs->flags & SCSI_DATA_IN) != 0)
            op = BUS_DMASYNC_PREREAD;
        else
            op = BUS_DMASYNC_PREWRITE;

        bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
                        scb->dmamap->dm_mapsize, op);

    }

    ahd_lock(ahd, &s);

    /*
     * Last time we need to check if this SCB needs to
     * be aborted.
     */
    if (xs->flags & ITSDONE) {
        if (nsegments != 0)
            bus_dmamap_unload(ahd->parent_dmat,
                              scb->dmamap);
        ahd_free_scb(ahd, scb);
        ahd_unlock(ahd, &s);
        return;
    }

    tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid),
                                SCSIID_OUR_ID(scb->hscb->scsiid),
                                SCSIID_TARGET(ahd, scb->hscb->scsiid),
                                &tstate);

    mask = SCB_GET_TARGET_MASK(ahd, scb);

    if ((tstate->discenable & mask) != 0)
        scb->hscb->control |= DISCENB;

    if ((tstate->tagenable & mask) != 0)
        scb->hscb->control |= TAG_ENB;

    if ((tinfo->curr.ppr_options & MSG_EXT_PPR_PROT_IUS) != 0) {
        scb->flags |= SCB_PACKETIZED;
        if (scb->hscb->task_management != 0)
            scb->hscb->control &= ~MK_MESSAGE;
    }

    if ((tstate->auto_negotiate & mask) != 0) {
        scb->flags |= SCB_AUTO_NEGOTIATE;
        scb->hscb->control |= MK_MESSAGE;
    }

    /* XXX with ahc there was some bus_dmamap_sync(PREREAD|PREWRITE); */

    LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);

    if (!(xs->flags & SCSI_POLL))
        timeout_add_msec(&xs->stimeout, xs->timeout);

    scb->flags |= SCB_ACTIVE;

    if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
        /* Define a mapping from our tag to the SCB. */
        ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
        ahd_pause(ahd);
        ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
        ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG);
        ahd_unpause(ahd);
    } else {
        ahd_queue_scb(ahd, scb);
    }

    if (!(xs->flags & SCSI_POLL)) {
        int target = xs->sc_link->target;
        int lun = SCB_GET_LUN(scb);

        if (ahd->inited_target[target] == 0) {
            struct  ahd_devinfo devinfo;

            ahd_adapter_req_set_xfer_mode(ahd, scb);
            ahd_compile_devinfo(&devinfo, ahd->our_id, target, lun,
                                'A', /*XXX milos*/ROLE_UNKNOWN);
            ahd_scb_devinfo(ahd, &devinfo, scb);
            ahd_update_neg_request(ahd, &devinfo, tstate, tinfo,
                                   AHD_NEG_IF_NON_ASYNC);
            ahd->inited_target[target] = 1;
        }

        ahd_unlock(ahd, &s);
        return;
    }

    /*
     * If we can't use interrupts, poll for completion
     */
    SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_poll\n"));

    do {
        if (ahd_poll(ahd, xs->timeout)) {
            if (!(xs->flags & SCSI_SILENT))
                printf("cmd fail\n");
            ahd_timeout(scb);
            break;
        }
    } while (!(xs->flags & ITSDONE));

    ahd_unlock(ahd, &s);
}
Пример #9
0
void
ahd_action(struct scsi_xfer *xs)
{
    struct	ahd_softc *ahd;
    struct scb *scb;
    struct hardware_scb *hscb;
    u_int	target_id;
    u_int	our_id;
    int	s;
    struct	ahd_initiator_tinfo *tinfo;
    struct	ahd_tmode_tstate *tstate;
    u_int	col_idx;
    u_int16_t quirks;

    SC_DEBUG(xs->sc_link, SDEV_DB3, ("ahd_action\n"));
    ahd = (struct ahd_softc *)xs->sc_link->adapter_softc;

    target_id = xs->sc_link->target;
    our_id = SCSI_SCSI_ID(ahd, xs->sc_link);

    ahd_lock(ahd, &s);
    if ((ahd->flags & AHD_INITIATORROLE) == 0) {
        xs->error = XS_DRIVER_STUFFUP;
        scsi_done(xs);
        ahd_unlock(ahd, &s);
        return;
    }
    /*
     * get an scb to use.
     */
    tinfo = ahd_fetch_transinfo(ahd, 'A', our_id, target_id, &tstate);

    quirks = xs->sc_link->quirks;

    if ((quirks & SDEV_NOTAGS) != 0 ||
            (tinfo->curr.ppr_options & MSG_EXT_PPR_PROT_IUS) != 0)
        col_idx = AHD_NEVER_COL_IDX;
    else
        col_idx = AHD_BUILD_COL_IDX(target_id, xs->sc_link->lun);

    if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
        ahd->flags |= AHD_RESOURCE_SHORTAGE;
        xs->error = XS_NO_CCB;
        scsi_done(xs);
        ahd_unlock(ahd, &s);
        return;
    }
    ahd_unlock(ahd, &s);

    hscb = scb->hscb;

    SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb));

    scb->xs = xs;
    timeout_set(&xs->stimeout, ahd_timeout, scb);

    /*
     * Put all the arguments for the xfer in the scb
     */
    hscb->control = 0;
    hscb->scsiid = BUILD_SCSIID(ahd, xs->sc_link, target_id, our_id);
    hscb->lun = xs->sc_link->lun;
    if (xs->xs_control & XS_CTL_RESET) {
        hscb->cdb_len = 0;
        scb->flags |= SCB_DEVICE_RESET;
        hscb->control |= MK_MESSAGE;
        hscb->task_management = SIU_TASKMGMT_LUN_RESET;
        ahd_execute_scb(scb, NULL, 0);
    } else {
        hscb->task_management = 0;
        ahd_setup_data(ahd, xs, scb);
    }
}
Пример #10
0
/*
 * We have an scb which has been processed by the
 * adaptor, now we look to see how the operation
 * went.
 */
void
ahd_done(struct ahd_softc *ahd, struct scb *scb)
{
    struct scsi_xfer *xs = scb->xs;
    int s;

    /* XXX in ahc there is some bus_dmamap_sync(PREREAD|PREWRITE); */

    LIST_REMOVE(scb, pending_links);

    timeout_del(&xs->stimeout);

    if (xs->datalen) {
        int op;

        if ((xs->flags & SCSI_DATA_IN) != 0)
            op = BUS_DMASYNC_POSTREAD;
        else
            op = BUS_DMASYNC_POSTWRITE;
        bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
                        scb->dmamap->dm_mapsize, op);
        bus_dmamap_unload(ahd->parent_dmat, scb->dmamap);
    }

    /* Translate the CAM status code to a SCSI error code. */
    switch (xs->error) {
    case CAM_SCSI_STATUS_ERROR:
    case CAM_REQ_INPROG:
    case CAM_REQ_CMP:
        switch (xs->status) {
        case SCSI_TASKSET_FULL:
        case SCSI_BUSY:
            xs->error = XS_BUSY;
            break;
        case SCSI_CHECK:
        case SCSI_TERMINATED:
            if ((scb->flags & SCB_SENSE) == 0) {
                /* CHECK on CHECK? */
                xs->error = XS_DRIVER_STUFFUP;
            } else
                xs->error = XS_NOERROR;
            break;
        default:
            xs->error = XS_NOERROR;
            break;
        }
        break;
    case CAM_BUSY:
    case CAM_REQUEUE_REQ:
        xs->error = XS_BUSY;
        break;
    case CAM_CMD_TIMEOUT:
        xs->error = XS_TIMEOUT;
        break;
    case CAM_BDR_SENT:
    case CAM_SCSI_BUS_RESET:
        xs->error = XS_RESET;
        break;
    case CAM_SEL_TIMEOUT:
        xs->error = XS_SELTIMEOUT;
        break;
    default:
        xs->error = XS_DRIVER_STUFFUP;
        break;
    }

    if (xs->error != XS_NOERROR) {
        /* Don't clobber any existing error state */
    } else if ((scb->flags & SCB_SENSE) != 0) {
        /*
         * We performed autosense retrieval.
         *
         * Zero any sense not transferred by the
         * device.  The SCSI spec mandates that any
         * untransferred data should be assumed to be
         * zero.  Complete the 'bounce' of sense information
         * through buffers accessible via bus-space by
         * copying it into the clients csio.
         */
        memset(&xs->sense, 0, sizeof(struct scsi_sense_data));
        memcpy(&xs->sense, ahd_get_sense_buf(ahd, scb),
               sizeof(struct scsi_sense_data));
        xs->error = XS_SENSE;
    } else if ((scb->flags & SCB_PKT_SENSE) != 0) {
        struct scsi_status_iu_header *siu;
        u_int32_t len;

        siu = (struct scsi_status_iu_header *)scb->sense_data;
        len = SIU_SENSE_LENGTH(siu);
        memset(&xs->sense, 0, sizeof(xs->sense));
        memcpy(&xs->sense, SIU_SENSE_DATA(siu),
               ulmin(len, sizeof(xs->sense)));
        xs->error = XS_SENSE;
    }

    ahd_lock(ahd, &s);
    ahd_free_scb(ahd, scb);
    scsi_done(xs);
    ahd_unlock(ahd, &s);
}