static void hpt_io_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { PCOMMAND pCmd = (PCOMMAND)arg; POS_CMDEXT ext = (POS_CMDEXT)pCmd->priv; PSG psg = pCmd->psg; int idx; HPT_ASSERT(pCmd->flags.physical_sg); if (error) panic("busdma error"); HPT_ASSERT(nsegs<=os_max_sg_descriptors); if (nsegs != 0) { for (idx = 0; idx < nsegs; idx++, psg++) { psg->addr.bus = segs[idx].ds_addr; psg->size = segs[idx].ds_len; psg->eot = 0; } psg[-1].eot = 1; if (pCmd->flags.data_in) { bus_dmamap_sync(ext->vbus_ext->io_dmat, ext->dma_map, BUS_DMASYNC_PREREAD); } else if (pCmd->flags.data_out) { bus_dmamap_sync(ext->vbus_ext->io_dmat, ext->dma_map, BUS_DMASYNC_PREWRITE); } } callout_reset(&ext->timeout, HPT_OSM_TIMEOUT, hpt_timeout, pCmd); ldm_queue_cmd(pCmd); }
static int hpt_alloc_mem(PVBUS_EXT vbus_ext) { PHBA hba; struct freelist *f; HPT_UINT i; void **p; for (hba = vbus_ext->hba_list; hba; hba = hba->next) hba->ldm_adapter.him->get_meminfo(hba->ldm_adapter.him_handle); ldm_get_mem_info((PVBUS)vbus_ext->vbus, 0); for (f=vbus_ext->freelist_head; f; f=f->next) { KdPrint(("%s: %d*%d=%d bytes", f->tag, f->count, f->size, f->count*f->size)); for (i=0; i<f->count; i++) { p = (void **)malloc(f->size, M_DEVBUF, M_WAITOK); if (!p) return (ENXIO); *p = f->head; f->head = p; } } for (f=vbus_ext->freelist_dma_head; f; f=f->next) { int order, size, j; HPT_ASSERT((f->size & (f->alignment-1))==0); for (order=0, size=PAGE_SIZE; size<f->size; order++, size<<=1) ; KdPrint(("%s: %d*%d=%d bytes, order %d", f->tag, f->count, f->size, f->count*f->size, order)); HPT_ASSERT(f->alignment<=PAGE_SIZE); for (i=0; i<f->count;) { p = (void **)__get_free_pages(order); if (!p) return -1; for (j = size/f->size; j && i<f->count; i++,j--) { *p = f->head; *(BUS_ADDRESS *)(p+1) = (BUS_ADDRESS)vtophys(p); f->head = p; p = (void **)((unsigned long)p + f->size); } } } HPT_ASSERT(PAGE_SIZE==DMAPOOL_PAGE_SIZE); for (i=0; i<os_max_cache_pages; i++) { p = (void **)__get_free_pages(0); if (!p) return -1; HPT_ASSERT(((HPT_UPTR)p & (DMAPOOL_PAGE_SIZE-1))==0); dmapool_put_page((PVBUS)vbus_ext->vbus, p, (BUS_ADDRESS)vtophys(p)); } return 0; }
void freelist_put(struct freelist * list, void *p) { HPT_ASSERT(list->dma==0); list->count++; *(void **)p = list->head; list->head = p; }
static int os_buildsgl(PCOMMAND pCmd, PSG pSg, int logical) { POS_CMDEXT ext = (POS_CMDEXT)pCmd->priv; union ccb *ccb = ext->ccb; bus_dma_segment_t *sgList = (bus_dma_segment_t *)ccb->csio.data_ptr; int idx; if(logical) { if (ccb->ccb_h.flags & CAM_DATA_PHYS) panic("physical address unsupported"); if (ccb->ccb_h.flags & CAM_SCATTER_VALID) { if (ccb->ccb_h.flags & CAM_SG_LIST_PHYS) panic("physical address unsupported"); for (idx = 0; idx < ccb->csio.sglist_cnt; idx++) { os_set_sgptr(&pSg[idx], (HPT_U8 *)(HPT_UPTR)sgList[idx].ds_addr); pSg[idx].size = sgList[idx].ds_len; pSg[idx].eot = (idx==ccb->csio.sglist_cnt-1)? 1 : 0; } } else { os_set_sgptr(pSg, (HPT_U8 *)ccb->csio.data_ptr); pSg->size = ccb->csio.dxfer_len; pSg->eot = 1; } return TRUE; } /* since we have provided physical sg, nobody will ask us to build physical sg */ HPT_ASSERT(0); return FALSE; }
static int hpt_delete_array(_VBUS_ARG DEVICEID id, DWORD options) { PVDevice pArray = ID_TO_VDEV(id); BOOLEAN del_block0 = (options & DAF_KEEP_DATA_IF_POSSIBLE)?0:1; int i; PVDevice pa; if ((id==0) || check_VDevice_valid(pArray)) return -1; if(!mIsArray(pArray)) return -1; if (pArray->u.array.rf_rebuilding || pArray->u.array.rf_verifying || pArray->u.array.rf_initializing) return -1; for(i=0; i<pArray->u.array.bArnMember; i++) { pa = pArray->u.array.pMember[i]; if (pa && mIsArray(pa)) { if (pa->u.array.rf_rebuilding || pa->u.array.rf_verifying || pa->u.array.rf_initializing) return -1; } } if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;} fDeleteArray(_VBUS_P pArray, del_block0); return 0; }
void freelist_put_dma(struct freelist *list, void *p, BUS_ADDRESS busaddr) { HPT_ASSERT(list->dma); list->count++; *(void **)p = list->head; *(BUS_ADDRESS *)((void **)p+1) = busaddr; list->head = p; }
void os_request_timer(void * osext, HPT_U32 interval) { PVBUS_EXT vbus_ext = osext; HPT_ASSERT(vbus_ext->ext_type==EXT_TYPE_VBUS); callout_reset(&vbus_ext->timer, interval * hz / 1000000, os_timer_for_ldm, vbus_ext); }
void os_request_timer(void * osext, HPT_U32 interval) { PVBUS_EXT vbus_ext = osext; HPT_ASSERT(vbus_ext->ext_type==EXT_TYPE_VBUS); callout_reset_sbt(&vbus_ext->timer, SBT_1US * interval, 0, os_timer_for_ldm, vbus_ext, 0); }
void os_request_timer(void * osext, HPT_U32 interval) { PVBUS_EXT vbus_ext = osext; HPT_ASSERT(vbus_ext->ext_type==EXT_TYPE_VBUS); untimeout(os_timer_for_ldm, vbus_ext, vbus_ext->timer); vbus_ext->timer = timeout(os_timer_for_ldm, vbus_ext, interval * hz / 1000000); }
void *freelist_get_dma(struct freelist *list, BUS_ADDRESS *busaddr) { void *result; HPT_ASSERT(list->dma); result = freelist_get(list); if (result) *busaddr = *(BUS_ADDRESS *)((void **)result+1); return result; }
void *freelist_get(struct freelist *list) { void * result; if (list->count) { HPT_ASSERT(list->head); result = list->head; list->head = *(void **)result; list->count--; return result; } return 0; }
void os_request_timer(void * osext, HPT_U32 interval) { PVBUS_EXT vbus_ext = osext; HPT_ASSERT(vbus_ext->ext_type==EXT_TYPE_VBUS); #if (__FreeBSD_version >= 1000510) callout_reset_sbt(&vbus_ext->timer, SBT_1US * interval, 0, os_timer_for_ldm, vbus_ext, 0); #else untimeout(os_timer_for_ldm, vbus_ext, vbus_ext->timer); vbus_ext->timer = timeout(os_timer_for_ldm, vbus_ext, interval * hz / 1000000); #endif }
static int os_buildsgl(PCOMMAND pCmd, PSG pSg, int logical) { POS_CMDEXT ext = (POS_CMDEXT)pCmd->priv; union ccb *ccb = ext->ccb; if (logical) { os_set_sgptr(pSg, (HPT_U8 *)ccb->csio.data_ptr); pSg->size = ccb->csio.dxfer_len; pSg->eot = 1; return TRUE; } /* since we have provided physical sg, nobody will ask us to build physical sg */ HPT_ASSERT(0); return FALSE; }
static void hpt_flush_done(PCOMMAND pCmd) { PVDEV vd = pCmd->target; if (mIsArray(vd->type) && vd->u.array.transform && vd!=vd->u.array.transform->target) { vd = vd->u.array.transform->target; HPT_ASSERT(vd); pCmd->target = vd; pCmd->Result = RETURN_PENDING; vdev_queue_cmd(pCmd); return; } *(int *)pCmd->priv = 1; wakeup(pCmd); }
static void hpt_free_mem(PVBUS_EXT vbus_ext) { struct freelist *f; void *p; int i; BUS_ADDRESS bus; for (f=vbus_ext->freelist_head; f; f=f->next) { #if DBG if (f->count!=f->reserved_count) { KdPrint(("memory leak for freelist %s (%d/%d)", f->tag, f->count, f->reserved_count)); } #endif while ((p=freelist_get(f))) free(p, M_DEVBUF); } for (i=0; i<os_max_cache_pages; i++) { p = dmapool_get_page((PVBUS)vbus_ext->vbus, &bus); HPT_ASSERT(p); free_pages(p, 0); } for (f=vbus_ext->freelist_dma_head; f; f=f->next) { int order, size; #if DBG if (f->count!=f->reserved_count) { KdPrint(("memory leak for dma freelist %s (%d/%d)", f->tag, f->count, f->reserved_count)); } #endif for (order=0, size=PAGE_SIZE; size<f->size; order++, size<<=1) ; while ((p=freelist_get_dma(f, &bus))) { if (order) free_pages(p, order); else { /* can't free immediately since other blocks in this page may still be in the list */ if (((HPT_UPTR)p & (PAGE_SIZE-1))==0) dmapool_put_page((PVBUS)vbus_ext->vbus, p, bus); } } } while ((p = dmapool_get_page((PVBUS)vbus_ext->vbus, &bus))) free_pages(p, 0); }
void os_schedule_task(void *osext, OSM_TASK *task) { PVBUS_EXT vbus_ext = osext; HPT_ASSERT(task->next==0); if (vbus_ext->tasks==0) vbus_ext->tasks = task; else { OSM_TASK *t = vbus_ext->tasks; while (t->next) t = t->next; t->next = task; } if (vbus_ext->worker.ta_context) TASK_ENQUEUE(&vbus_ext->worker); }
static void hpt_scsi_io(PVBUS_EXT vbus_ext, union ccb *ccb) { PVBUS vbus = (PVBUS)vbus_ext->vbus; PVDEV vd; PCOMMAND pCmd; POS_CMDEXT ext; HPT_U8 *cdb; if (ccb->ccb_h.flags & CAM_CDB_POINTER) cdb = ccb->csio.cdb_io.cdb_ptr; else cdb = ccb->csio.cdb_io.cdb_bytes; KdPrint(("hpt_scsi_io: ccb %x id %d lun %d cdb %x-%x-%x", ccb, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, *(HPT_U32 *)&cdb[0], *(HPT_U32 *)&cdb[4], *(HPT_U32 *)&cdb[8] )); /* ccb->ccb_h.path_id is not our bus id - don't check it */ if (ccb->ccb_h.target_lun != 0 || ccb->ccb_h.target_id >= osm_max_targets || (ccb->ccb_h.flags & CAM_CDB_PHYS)) { ccb->ccb_h.status = CAM_TID_INVALID; xpt_done(ccb); return; } vd = ldm_find_target(vbus, ccb->ccb_h.target_id); if (!vd) { ccb->ccb_h.status = CAM_TID_INVALID; xpt_done(ccb); return; } switch (cdb[0]) { case TEST_UNIT_READY: case START_STOP_UNIT: case SYNCHRONIZE_CACHE: ccb->ccb_h.status = CAM_REQ_CMP; break; case INQUIRY: { PINQUIRYDATA inquiryData; memset(ccb->csio.data_ptr, 0, ccb->csio.dxfer_len); inquiryData = (PINQUIRYDATA)ccb->csio.data_ptr; inquiryData->AdditionalLength = 31; inquiryData->CommandQueue = 1; memcpy(&inquiryData->VendorId, "HPT ", 8); memcpy(&inquiryData->ProductId, "DISK 0_0 ", 16); if (vd->target_id / 10) { inquiryData->ProductId[7] = (vd->target_id % 100) / 10 + '0'; inquiryData->ProductId[8] = (vd->target_id % 100) % 10 + '0'; } else inquiryData->ProductId[7] = (vd->target_id % 100) % 10 + '0'; memcpy(&inquiryData->ProductRevisionLevel, "4.00", 4); ccb->ccb_h.status = CAM_REQ_CMP; } break; case READ_CAPACITY: { HPT_U8 *rbuf = ccb->csio.data_ptr; HPT_U32 cap; if (vd->capacity>0xfffffffful) cap = 0xfffffffful; else cap = vd->capacity - 1; rbuf[0] = (HPT_U8)(cap>>24); rbuf[1] = (HPT_U8)(cap>>16); rbuf[2] = (HPT_U8)(cap>>8); rbuf[3] = (HPT_U8)cap; rbuf[4] = 0; rbuf[5] = 0; rbuf[6] = 2; rbuf[7] = 0; ccb->ccb_h.status = CAM_REQ_CMP; break; } case SERVICE_ACTION_IN: { HPT_U8 *rbuf = ccb->csio.data_ptr; HPT_U64 cap = vd->capacity - 1; rbuf[0] = (HPT_U8)(cap>>56); rbuf[1] = (HPT_U8)(cap>>48); rbuf[2] = (HPT_U8)(cap>>40); rbuf[3] = (HPT_U8)(cap>>32); rbuf[4] = (HPT_U8)(cap>>24); rbuf[5] = (HPT_U8)(cap>>16); rbuf[6] = (HPT_U8)(cap>>8); rbuf[7] = (HPT_U8)cap; rbuf[8] = 0; rbuf[9] = 0; rbuf[10] = 2; rbuf[11] = 0; ccb->ccb_h.status = CAM_REQ_CMP; break; } case READ_6: case READ_10: case READ_16: case WRITE_6: case WRITE_10: case WRITE_16: case 0x13: case 0x2f: case 0x8f: /* VERIFY_16 */ { int error; pCmd = ldm_alloc_cmds(vbus, vd->cmds_per_request); if(!pCmd){ KdPrint(("Failed to allocate command!")); ccb->ccb_h.status = CAM_BUSY; break; } switch (cdb[0]) { case READ_6: case WRITE_6: case 0x13: pCmd->uCmd.Ide.Lba = ((HPT_U32)cdb[1] << 16) | ((HPT_U32)cdb[2] << 8) | (HPT_U32)cdb[3]; pCmd->uCmd.Ide.nSectors = (HPT_U16) cdb[4]; break; case READ_16: case WRITE_16: case 0x8f: /* VERIFY_16 */ { HPT_U64 block = ((HPT_U64)cdb[2]<<56) | ((HPT_U64)cdb[3]<<48) | ((HPT_U64)cdb[4]<<40) | ((HPT_U64)cdb[5]<<32) | ((HPT_U64)cdb[6]<<24) | ((HPT_U64)cdb[7]<<16) | ((HPT_U64)cdb[8]<<8) | ((HPT_U64)cdb[9]); pCmd->uCmd.Ide.Lba = block; pCmd->uCmd.Ide.nSectors = (HPT_U16)cdb[13] | ((HPT_U16)cdb[12]<<8); break; } default: pCmd->uCmd.Ide.Lba = (HPT_U32)cdb[5] | ((HPT_U32)cdb[4] << 8) | ((HPT_U32)cdb[3] << 16) | ((HPT_U32)cdb[2] << 24); pCmd->uCmd.Ide.nSectors = (HPT_U16) cdb[8] | ((HPT_U16)cdb[7]<<8); break; } switch (cdb[0]) { case READ_6: case READ_10: case READ_16: pCmd->flags.data_in = 1; break; case WRITE_6: case WRITE_10: case WRITE_16: pCmd->flags.data_out = 1; break; } pCmd->priv = ext = cmdext_get(vbus_ext); HPT_ASSERT(ext); ext->ccb = ccb; pCmd->target = vd; pCmd->done = os_cmddone; pCmd->buildsgl = os_buildsgl; pCmd->psg = ext->psg; pCmd->flags.physical_sg = 1; error = bus_dmamap_load_ccb(vbus_ext->io_dmat, ext->dma_map, ccb, hpt_io_dmamap_callback, pCmd, BUS_DMA_WAITOK ); KdPrint(("bus_dmamap_load return %d", error)); if (error && error!=EINPROGRESS) { os_printk("bus_dmamap_load error %d", error); cmdext_put(ext); ldm_free_cmds(pCmd); ccb->ccb_h.status = CAM_REQ_CMP_ERR; xpt_done(ccb); } return; } default: ccb->ccb_h.status = CAM_REQ_INVALID; break; } xpt_done(ccb); return; }
static int os_buildsgl(PCOMMAND pCmd, PSG pSg, int logical) { /* since we have provided physical sg, nobody will ask us to build physical sg */ HPT_ASSERT(0); return FALSE; }
void hpt_rebuild_data_block(IAL_ADAPTER_T *pAdapter, PVDevice pArray, UCHAR flags) { ULONG capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember-1); PCommand pCmd; UINT result; int needsync=0, retry=0, needdelete=0; void *buffer = NULL; _VBUS_INST(&pAdapter->VBus) if (pArray->u.array.rf_broken==1 || pArray->u.array.RebuildSectors>=capacity) return; mtx_lock(&pAdapter->lock); switch(flags) { case DUPLICATE: case REBUILD_PARITY: if(pArray->u.array.rf_rebuilding == 0) { pArray->u.array.rf_rebuilding = 1; hpt_printk(("Rebuilding started.\n")); ioctl_ReportEvent(ET_REBUILD_STARTED, pArray); } break; case INITIALIZE: if(pArray->u.array.rf_initializing == 0) { pArray->u.array.rf_initializing = 1; hpt_printk(("Initializing started.\n")); ioctl_ReportEvent(ET_INITIALIZE_STARTED, pArray); } break; case VERIFY: if(pArray->u.array.rf_verifying == 0) { pArray->u.array.rf_verifying = 1; hpt_printk(("Verifying started.\n")); ioctl_ReportEvent(ET_VERIFY_STARTED, pArray); } break; } retry_cmd: pCmd = AllocateCommand(_VBUS_P0); HPT_ASSERT(pCmd); pCmd->cf_control = 1; End_Job = 0; if (pArray->VDeviceType==VD_RAID_1) { #define MAX_REBUILD_SECTORS 0x40 /* take care for discontinuous buffer in R1ControlSgl */ buffer = malloc(SECTOR_TO_BYTE(MAX_REBUILD_SECTORS), M_DEVBUF, M_NOWAIT); if(!buffer) { FreeCommand(_VBUS_P pCmd); hpt_printk(("can't allocate rebuild buffer\n")); goto fail; } switch(flags) { case DUPLICATE: pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD; pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS; break; case VERIFY: pCmd->uCmd.R1Control.Command = CTRL_CMD_VERIFY; pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS/2; break; case INITIALIZE: pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD; pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS; break; } pCmd->uCmd.R1Control.Lba = pArray->u.array.RebuildSectors; if (capacity - pArray->u.array.RebuildSectors < pCmd->uCmd.R1Control.nSectors) pCmd->uCmd.R1Control.nSectors = capacity - pArray->u.array.RebuildSectors; pCmd->uCmd.R1Control.Buffer = buffer; pCmd->pfnBuildSgl = R1ControlSgl; } else if (pArray->VDeviceType==VD_RAID_5) { switch(flags) { case DUPLICATE: case REBUILD_PARITY: pCmd->uCmd.R5Control.Command = CTRL_CMD_REBUILD; break; case VERIFY: pCmd->uCmd.R5Control.Command = CTRL_CMD_VERIFY; break; case INITIALIZE: pCmd->uCmd.R5Control.Command = CTRL_CMD_INIT; break; } pCmd->uCmd.R5Control.StripeLine=pArray->u.array.RebuildSectors>>pArray->u.array.bArBlockSizeShift; } else