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); } }
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); }
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); }
/* * 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"); =======
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); }
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); }
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); }
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); } }
/* * 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); }