Date: Wed, 21 Jul 2010 18:50:24 +0000 (UTC) From: Xin LI <delphij@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r210358 - head/sys/dev/arcmsr Message-ID: <201007211850.o6LIoON6007938@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: delphij Date: Wed Jul 21 18:50:24 2010 New Revision: 210358 URL: http://svn.freebsd.org/changeset/base/210358 Log: Apply vendor version 1.20.00.17. This version adds support for ARC1880; additionally this version fixed an issue where all devices on a SAS port gets offlined when any device failed on the port [1]. Many thanks to Areca for continuing to support FreeBSD. PR: kern/148502 [1] Submitted by: Ching-Lung Huang <ching2048 areca com tw> Obtained from: Areca Tested by: Rich Ercolani <rercola acm jhu edu> [1] MFC after: 2 weeks Modified: head/sys/dev/arcmsr/arcmsr.c head/sys/dev/arcmsr/arcmsr.h Modified: head/sys/dev/arcmsr/arcmsr.c ============================================================================== --- head/sys/dev/arcmsr/arcmsr.c Wed Jul 21 18:47:52 2010 (r210357) +++ head/sys/dev/arcmsr/arcmsr.c Wed Jul 21 18:50:24 2010 (r210358) @@ -2,15 +2,15 @@ ***************************************************************************************** ** O.S : FreeBSD ** FILE NAME : arcmsr.c -** BY : Erich Chen +** BY : Erich Chen, Ching Huang ** Description: SCSI RAID Device Driver for -** ARECA (ARC11XX/ARC12XX/ARC13XX/ARC16XX) SATA/SAS RAID HOST Adapter +** ARECA (ARC11XX/ARC12XX/ARC13XX/ARC16XX/ARC188x) SATA/SAS RAID HOST Adapter ** ARCMSR RAID Host adapter ** [RAID controller:INTEL 331(PCI-X) 341(PCI-EXPRESS) chip set] ****************************************************************************************** ************************************************************************ ** -** Copyright (c) 2004-2006 ARECA Co. Ltd. +** Copyright (c) 2004-2010 ARECA Co. Ltd. ** Erich Chen, Taipei Taiwan All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -57,6 +57,10 @@ ** 1.20.00.15 10/10/2007 Erich Chen support new RAID adapter type ARC120x ** 1.20.00.16 10/10/2009 Erich Chen Bug fix for RAID adapter type ARC120x ** bus_dmamem_alloc() with BUS_DMA_ZERO +** 1.20.00.17 07/15/2010 Ching Huang Added support ARC1880 +** report CAM_DEV_NOT_THERE instead of CAM_SEL_TIMEOUT when device failed, +** prevent cam_periph_error removing all LUN devices of one Target id +** for any one LUN device failed ****************************************************************************************** * $FreeBSD$ */ @@ -90,6 +94,8 @@ #include <cam/cam.h> #include <cam/cam_ccb.h> #include <cam/cam_sim.h> +#include <cam/cam_periph.h> +#include <cam/cam_xpt_periph.h> #include <cam/cam_xpt_sim.h> #include <cam/cam_debug.h> #include <cam/scsi/scsi_all.h> @@ -165,6 +171,8 @@ static void arcmsr_build_srb(struct Comm static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, union ccb * pccb); static int arcmsr_resume(device_t dev); static int arcmsr_suspend(device_t dev); +static void arcmsr_rescanLun_cb(struct cam_periph *periph, union ccb *ccb); +static void arcmsr_polling_devmap(void* arg); /* ************************************************************************** ************************************************************************** @@ -191,7 +199,6 @@ static device_method_t arcmsr_methods[]= DEVMETHOD(device_shutdown, arcmsr_shutdown), DEVMETHOD(device_suspend, arcmsr_suspend), DEVMETHOD(device_resume, arcmsr_resume), - DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_driver_added, bus_generic_driver_added), { 0, 0 } @@ -215,7 +222,7 @@ MODULE_DEPEND(arcmsr, cam, 1, 1, 1); #ifndef D_VERSION #define D_VERSION 0x20011966 #endif - static struct cdevsw arcmsr_cdevsw={ +static struct cdevsw arcmsr_cdevsw={ #if __FreeBSD_version > 502010 .d_version = D_VERSION, #endif @@ -228,7 +235,7 @@ MODULE_DEPEND(arcmsr, cam, 1, 1, 1); #else #define ARCMSR_CDEV_MAJOR 180 - static struct cdevsw arcmsr_cdevsw = { +static struct cdevsw arcmsr_cdevsw = { arcmsr_open, /* open */ arcmsr_close, /* close */ noread, /* read */ @@ -244,7 +251,10 @@ MODULE_DEPEND(arcmsr, cam, 1, 1, 1); 0 /* flags */ }; #endif - +/* +************************************************************************** +************************************************************************** +*/ #if __FreeBSD_version < 500005 static int arcmsr_open(dev_t dev, int flags, int fmt, struct proc *proc) #else @@ -328,18 +338,21 @@ static u_int32_t arcmsr_disable_allintr( switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { /* disable all outbound interrupt */ - intmask_org=CHIP_REG_READ32(HBA_MessageUnit, - 0, outbound_intmask)|ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE; /* disable outbound message0 int */ - CHIP_REG_WRITE32(HBA_MessageUnit, - 0, outbound_intmask, intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE); + intmask_org=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intmask); /* disable outbound message0 int */ + CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intmask, intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE); } break; case ACB_ADAPTER_TYPE_B: { /* disable all outbound interrupt */ intmask_org=CHIP_REG_READ32(HBB_DOORBELL, 0, iop2drv_doorbell_mask) & (~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); /* disable outbound message0 int */ - CHIP_REG_WRITE32(HBB_DOORBELL, - 0, iop2drv_doorbell_mask, 0); /* disable all interrupt */ + CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell_mask, 0); /* disable all interrupt */ + } + break; + case ACB_ADAPTER_TYPE_C: { + /* disable all outbound interrupt */ + intmask_org=CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_mask) ; /* disable outbound message0 int */ + CHIP_REG_WRITE32(HBC_MessageUnit, 0, host_int_mask, intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE); } break; } @@ -356,19 +369,25 @@ static void arcmsr_enable_allintr( struc switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { /* enable outbound Post Queue, outbound doorbell Interrupt */ - mask=~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE|ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); + mask=~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE|ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE); CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intmask, intmask_org & mask); acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; } break; case ACB_ADAPTER_TYPE_B: { - /* disable ARCMSR_IOP2DRV_MESSAGE_CMD_DONE */ - mask=(ARCMSR_IOP2DRV_DATA_WRITE_OK|ARCMSR_IOP2DRV_DATA_READ_OK|ARCMSR_IOP2DRV_CDB_DONE); - CHIP_REG_WRITE32(HBB_DOORBELL, - 0, iop2drv_doorbell_mask, intmask_org | mask); /*1=interrupt enable, 0=interrupt disable*/ + /* enable ARCMSR_IOP2DRV_MESSAGE_CMD_DONE */ + mask=(ARCMSR_IOP2DRV_DATA_WRITE_OK|ARCMSR_IOP2DRV_DATA_READ_OK|ARCMSR_IOP2DRV_CDB_DONE|ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); + CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell_mask, intmask_org | mask); /*1=interrupt enable, 0=interrupt disable*/ acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; } break; + case ACB_ADAPTER_TYPE_C: { + /* enable outbound Post Queue, outbound doorbell Interrupt */ + mask=~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK); + CHIP_REG_WRITE32(HBC_MessageUnit, 0, host_int_mask, intmask_org & mask); + acb->outbound_int_enable= ~(intmask_org & mask) & 0x0000000f; + } + break; } return; } @@ -383,10 +402,8 @@ static u_int8_t arcmsr_hba_wait_msgint_r do { for(Index=0; Index < 100; Index++) { - if(CHIP_REG_READ32(HBA_MessageUnit, - 0, outbound_intstatus) & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { - CHIP_REG_WRITE32(HBA_MessageUnit, - 0, outbound_intstatus, ARCMSR_MU_OUTBOUND_MESSAGE0_INT);/*clear interrupt*/ + if(CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intstatus) & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { + CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, ARCMSR_MU_OUTBOUND_MESSAGE0_INT);/*clear interrupt*/ return TRUE; } UDELAY(10000); @@ -405,12 +422,29 @@ static u_int8_t arcmsr_hbb_wait_msgint_r do { for(Index=0; Index < 100; Index++) { - if(CHIP_REG_READ32(HBB_DOORBELL, - 0, iop2drv_doorbell) & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { - CHIP_REG_WRITE32(HBB_DOORBELL, - 0, iop2drv_doorbell, ARCMSR_MESSAGE_INT_CLEAR_PATTERN);/*clear interrupt*/ - CHIP_REG_WRITE32(HBB_DOORBELL, - 0, drv2iop_doorbell, ARCMSR_DRV2IOP_END_OF_INTERRUPT); + if(CHIP_REG_READ32(HBB_DOORBELL, 0, iop2drv_doorbell) & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { + CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell, ARCMSR_MESSAGE_INT_CLEAR_PATTERN);/*clear interrupt*/ + CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_END_OF_INTERRUPT); + return TRUE; + } + UDELAY(10000); + }/*max 1 seconds*/ + }while(Retries++ < 20);/*max 20 sec*/ + return FALSE; +} +/* +********************************************************************** +********************************************************************** +*/ +static u_int8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *acb) +{ + u_int32_t Index; + u_int8_t Retries=0x00; + + do { + for(Index=0; Index < 100; Index++) { + if(CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { + CHIP_REG_WRITE32(HBC_MessageUnit, 0, outbound_doorbell_clear, ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR);/*clear interrupt*/ return TRUE; } UDELAY(10000); @@ -426,8 +460,7 @@ static void arcmsr_flush_hba_cache(struc { int retry_count=30;/* enlarge wait flush adapter cache time: 10 minute */ - CHIP_REG_WRITE32(HBA_MessageUnit, - 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_FLUSH_CACHE); + CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_FLUSH_CACHE); do { if(arcmsr_hba_wait_msgint_ready(acb)) { break; @@ -460,6 +493,25 @@ static void arcmsr_flush_hbb_cache(struc ************************************************************************ ************************************************************************ */ +static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *acb) +{ + int retry_count=30;/* enlarge wait flush adapter cache time: 10 minute */ + + CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_FLUSH_CACHE); + CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE); + do { + if(arcmsr_hbc_wait_msgint_ready(acb)) { + break; + } else { + retry_count--; + } + }while(retry_count!=0); + return; +} +/* +************************************************************************ +************************************************************************ +*/ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { @@ -471,6 +523,10 @@ static void arcmsr_flush_adapter_cache(s arcmsr_flush_hbb_cache(acb); } break; + case ACB_ADAPTER_TYPE_C: { + arcmsr_flush_hbc_cache(acb); + } + break; } return; } @@ -482,10 +538,10 @@ static int arcmsr_suspend(device_t dev) { struct AdapterControlBlock *acb = device_get_softc(dev); - /* disable all outbound interrupt */ - arcmsr_disable_allintr(acb); /* flush controller */ arcmsr_iop_parking(acb); + /* disable all outbound interrupt */ + arcmsr_disable_allintr(acb); return(0); } /* @@ -515,12 +571,10 @@ static void arcmsr_async(void *cb_arg, u case AC_LOST_DEVICE: target_id=xpt_path_target_id(path); target_lun=xpt_path_lun_id(path); - if((target_id > ARCMSR_MAX_TARGETID) - || (target_lun > ARCMSR_MAX_TARGETLUN)) { + if((target_id > ARCMSR_MAX_TARGETID) || (target_lun > ARCMSR_MAX_TARGETLUN)) { break; } - printf("%s:scsi id%d lun%d device lost \n" - , device_get_name(acb->pci_dev), target_id, target_lun); + printf("%s:scsi id=%d lun=%d device lost \n", device_get_name(acb->pci_dev), target_id, target_lun); break; default: break; @@ -589,8 +643,7 @@ static void arcmsr_abort_hba_allcmd(stru { CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_ABORT_CMD); if(!arcmsr_hba_wait_msgint_ready(acb)) { - printf("arcmsr%d: wait 'abort all outstanding command' timeout \n" - , acb->pci_unit); + printf("arcmsr%d: wait 'abort all outstanding command' timeout \n", acb->pci_unit); } return; } @@ -602,8 +655,20 @@ static void arcmsr_abort_hbb_allcmd(stru { CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_MESSAGE_ABORT_CMD); if(!arcmsr_hbb_wait_msgint_ready(acb)) { - printf("arcmsr%d: wait 'abort all outstanding command' timeout \n" - , acb->pci_unit); + printf("arcmsr%d: wait 'abort all outstanding command' timeout \n", acb->pci_unit); + } + return; +} +/* +********************************************************************* +********************************************************************* +*/ +static void arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *acb) +{ + CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_ABORT_CMD); + CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE); + if(!arcmsr_hbc_wait_msgint_ready(acb)) { + printf("arcmsr%d: wait 'abort all outstanding command' timeout \n", acb->pci_unit); } return; } @@ -622,6 +687,10 @@ static void arcmsr_abort_allcmd(struct A arcmsr_abort_hbb_allcmd(acb); } break; + case ACB_ADAPTER_TYPE_C: { + arcmsr_abort_hbc_allcmd(acb); + } + break; } return; } @@ -629,14 +698,13 @@ static void arcmsr_abort_allcmd(struct A ************************************************************************** ************************************************************************** */ -static void arcmsr_report_srb_state(struct AdapterControlBlock *acb, - struct CommandControlBlock *srb, u_int32_t flag_srb) +static void arcmsr_report_srb_state(struct AdapterControlBlock *acb, struct CommandControlBlock *srb, u_int16_t error) { int target, lun; target=srb->pccb->ccb_h.target_id; lun=srb->pccb->ccb_h.target_lun; - if((flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR)==0) { + if(error == FALSE) { if(acb->devstate[target][lun]==ARECA_RAID_GONE) { acb->devstate[target][lun]=ARECA_RAID_GOOD; } @@ -646,12 +714,10 @@ static void arcmsr_report_srb_state(stru switch(srb->arcmsr_cdb.DeviceStatus) { case ARCMSR_DEV_SELECT_TIMEOUT: { if(acb->devstate[target][lun]==ARECA_RAID_GOOD) { - printf( "arcmsr%d: select timeout" - ", raid volume was kicked out \n" - , acb->pci_unit); + printf( "arcmsr%d: Target=%x, Lun=%x, selection timeout, raid volume was lost\n", acb->pci_unit, target, lun); } acb->devstate[target][lun]=ARECA_RAID_GONE; - srb->pccb->ccb_h.status |= CAM_SEL_TIMEOUT; + srb->pccb->ccb_h.status |= CAM_DEV_NOT_THERE; arcmsr_srb_complete(srb, 1); } break; @@ -669,11 +735,8 @@ static void arcmsr_report_srb_state(stru } break; default: - printf("arcmsr%d: scsi id=%d lun=%d" - "isr get command error done," - "but got unknow DeviceStatus=0x%x \n" - , acb->pci_unit, target, lun - ,srb->arcmsr_cdb.DeviceStatus); + printf("arcmsr%d: scsi id=%d lun=%d isr got command error done,but got unknow DeviceStatus=0x%x \n" + , acb->pci_unit, target, lun ,srb->arcmsr_cdb.DeviceStatus); acb->devstate[target][lun]=ARECA_RAID_GONE; srb->pccb->ccb_h.status |= CAM_UNCOR_PARITY; /*unknow error or crc error just for retry*/ @@ -687,29 +750,34 @@ static void arcmsr_report_srb_state(stru ************************************************************************** ************************************************************************** */ -static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, u_int32_t flag_srb) +static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, u_int32_t flag_srb, u_int16_t error) { struct CommandControlBlock *srb; /* check if command done with no error*/ - srb=(struct CommandControlBlock *) - (acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_C: + srb = (struct CommandControlBlock *)(acb->vir2phy_offset+(flag_srb & 0xFFFFFFF0));/*frame must be 32 bytes aligned*/ + break; + case ACB_ADAPTER_TYPE_A: + case ACB_ADAPTER_TYPE_B: + default: + srb = (struct CommandControlBlock *)(acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/ + break; + } if((srb->acb!=acb) || (srb->startdone!=ARCMSR_SRB_START)) { if(srb->startdone==ARCMSR_SRB_ABORTED) { - printf("arcmsr%d: srb='%p' isr got aborted command \n" - , acb->pci_unit, srb); + printf("arcmsr%d: srb='%p' isr got aborted command \n", acb->pci_unit, srb); srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; arcmsr_srb_complete(srb, 1); return; } printf("arcmsr%d: isr get an illegal srb command done" - "acb='%p' srb='%p' srbacb='%p' startdone=0x%x" - "srboutstandingcount=%d \n", - acb->pci_unit, acb, srb, srb->acb, - srb->startdone, acb->srboutstandingcount); + "acb='%p' srb='%p' srbacb='%p' startdone=0x%xsrboutstandingcount=%d \n", + acb->pci_unit, acb, srb, srb->acb,srb->startdone, acb->srboutstandingcount); return; } - arcmsr_report_srb_state(acb, srb, flag_srb); + arcmsr_report_srb_state(acb, srb, error); return; } /* @@ -720,20 +788,18 @@ static void arcmsr_done4abort_postqueue( { int i=0; u_int32_t flag_srb; + u_int16_t error; switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { u_int32_t outbound_intstatus; /*clear and abort all outbound posted Q*/ - outbound_intstatus=CHIP_REG_READ32(HBA_MessageUnit, - 0, outbound_intstatus) & acb->outbound_int_enable; - CHIP_REG_WRITE32(HBA_MessageUnit, - 0, outbound_intstatus, outbound_intstatus);/*clear interrupt*/ - while(((flag_srb=CHIP_REG_READ32(HBA_MessageUnit, - 0, outbound_queueport)) != 0xFFFFFFFF) - && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { - arcmsr_drain_donequeue(acb, flag_srb); + outbound_intstatus=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intstatus) & acb->outbound_int_enable; + CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, outbound_intstatus);/*clear interrupt*/ + while(((flag_srb=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_queueport)) != 0xFFFFFFFF) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { + error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE; + arcmsr_drain_donequeue(acb, flag_srb, error); } } break; @@ -741,13 +807,12 @@ static void arcmsr_done4abort_postqueue( struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; /*clear all outbound posted Q*/ - CHIP_REG_WRITE32(HBB_DOORBELL, - 0, iop2drv_doorbell, - ARCMSR_DOORBELL_INT_CLEAR_PATTERN); /* clear doorbell interrupt */ + CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell, ARCMSR_DOORBELL_INT_CLEAR_PATTERN); /* clear doorbell interrupt */ for(i=0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { if((flag_srb=phbbmu->done_qbuffer[i])!=0) { phbbmu->done_qbuffer[i]=0; - arcmsr_drain_donequeue(acb, flag_srb); + error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE; + arcmsr_drain_donequeue(acb, flag_srb, error); } phbbmu->post_qbuffer[i]=0; }/*drain reply FIFO*/ @@ -755,6 +820,15 @@ static void arcmsr_done4abort_postqueue( phbbmu->postq_index=0; } break; + case ACB_ADAPTER_TYPE_C: { + + while((CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { + flag_srb=CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_queueport_low); + error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1)?TRUE:FALSE; + arcmsr_drain_donequeue(acb, flag_srb, error); + } + } + break; } return; } @@ -873,7 +947,10 @@ static void arcmsr_build_srb(struct Comm if( arccdbsize > 256) { arcmsr_cdb->Flags|=ARCMSR_CDB_FLAG_SGL_BSIZE; } + } else { + arcmsr_cdb->DataLength = 0; } + srb->arc_cdb_size=arccdbsize; return; } /* @@ -885,19 +962,16 @@ static void arcmsr_post_srb(struct Adapt u_int32_t cdb_shifted_phyaddr=(u_int32_t) srb->cdb_shifted_phyaddr; struct ARCMSR_CDB * arcmsr_cdb=(struct ARCMSR_CDB *)&srb->arcmsr_cdb; - bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, - (srb->srb_flags & SRB_FLAG_WRITE) ? BUS_DMASYNC_POSTWRITE:BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, (srb->srb_flags & SRB_FLAG_WRITE) ? BUS_DMASYNC_POSTWRITE:BUS_DMASYNC_POSTREAD); atomic_add_int(&acb->srboutstandingcount, 1); srb->startdone=ARCMSR_SRB_START; + switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { if(arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { - CHIP_REG_WRITE32(HBA_MessageUnit, - 0, inbound_queueport, - cdb_shifted_phyaddr|ARCMSR_SRBPOST_FLAG_SGL_BSIZE); + CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_queueport, cdb_shifted_phyaddr|ARCMSR_SRBPOST_FLAG_SGL_BSIZE); } else { - CHIP_REG_WRITE32(HBA_MessageUnit, - 0, inbound_queueport, cdb_shifted_phyaddr); + CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_queueport, cdb_shifted_phyaddr); } } break; @@ -909,17 +983,32 @@ static void arcmsr_post_srb(struct Adapt ending_index=((index+1)%ARCMSR_MAX_HBB_POSTQUEUE); phbbmu->post_qbuffer[ending_index]=0; if(arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { - phbbmu->post_qbuffer[index]= - cdb_shifted_phyaddr|ARCMSR_SRBPOST_FLAG_SGL_BSIZE; + phbbmu->post_qbuffer[index]= cdb_shifted_phyaddr|ARCMSR_SRBPOST_FLAG_SGL_BSIZE; } else { - phbbmu->post_qbuffer[index]= - cdb_shifted_phyaddr; + phbbmu->post_qbuffer[index]= cdb_shifted_phyaddr; } index++; index %= ARCMSR_MAX_HBB_POSTQUEUE; /*if last index number set it to 0 */ phbbmu->postq_index=index; - CHIP_REG_WRITE32(HBB_DOORBELL, - 0, drv2iop_doorbell, ARCMSR_DRV2IOP_CDB_POSTED); + CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_CDB_POSTED); + } + break; + case ACB_ADAPTER_TYPE_C: + { + u_int32_t ccb_post_stamp, arc_cdb_size, cdb_phyaddr_hi32; + + arc_cdb_size=(srb->arc_cdb_size>0x300)?0x300:srb->arc_cdb_size; + ccb_post_stamp=(cdb_shifted_phyaddr | ((arc_cdb_size-1) >> 6) | 1); + cdb_phyaddr_hi32 = acb->srb_phyaddr.B.phyadd_high; + if(cdb_phyaddr_hi32) + { + CHIP_REG_WRITE32(HBC_MessageUnit,0,inbound_queueport_high, cdb_phyaddr_hi32); + CHIP_REG_WRITE32(HBC_MessageUnit,0,inbound_queueport_low, ccb_post_stamp); + } + else + { + CHIP_REG_WRITE32(HBC_MessageUnit,0,inbound_queueport_low, ccb_post_stamp); + } } break; } @@ -946,6 +1035,12 @@ static struct QBUFFER * arcmsr_get_iop_r qbuffer=(struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_rbuffer; } break; + case ACB_ADAPTER_TYPE_C: { + struct HBC_MessageUnit *phbcmu=(struct HBC_MessageUnit *)acb->pmu; + + qbuffer=(struct QBUFFER *)&phbcmu->message_rbuffer; + } + break; } return(qbuffer); } @@ -970,6 +1065,12 @@ static struct QBUFFER * arcmsr_get_iop_w qbuffer=(struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_wbuffer; } break; + case ACB_ADAPTER_TYPE_C: { + struct HBC_MessageUnit *phbcmu=(struct HBC_MessageUnit *)acb->pmu; + + qbuffer=(struct QBUFFER *)&phbcmu->message_wbuffer; + } + break; } return(qbuffer); } @@ -982,16 +1083,18 @@ static void arcmsr_iop_message_read(stru switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { /* let IOP know data has been read */ - CHIP_REG_WRITE32(HBA_MessageUnit, - 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK); + CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK); } break; case ACB_ADAPTER_TYPE_B: { /* let IOP know data has been read */ - CHIP_REG_WRITE32(HBB_DOORBELL, - 0, drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_READ_OK); + CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_READ_OK); } break; + case ACB_ADAPTER_TYPE_C: { + /* let IOP know data has been read */ + CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK); + } } return; } @@ -1007,8 +1110,7 @@ static void arcmsr_iop_message_wrote(str ** push inbound doorbell tell iop, driver data write ok ** and wait reply on next hwinterrupt for next Qbuffer post */ - CHIP_REG_WRITE32(HBA_MessageUnit, - 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK); + CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK); } break; case ACB_ADAPTER_TYPE_B: { @@ -1016,8 +1118,15 @@ static void arcmsr_iop_message_wrote(str ** push inbound doorbell tell iop, driver data write ok ** and wait reply on next hwinterrupt for next Qbuffer post */ - CHIP_REG_WRITE32(HBB_DOORBELL, - 0, drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_WRITE_OK); + CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_WRITE_OK); + } + break; + case ACB_ADAPTER_TYPE_C: { + /* + ** push inbound doorbell tell iop, driver data write ok + ** and wait reply on next hwinterrupt for next Qbuffer post + */ + CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK); } break; } @@ -1064,7 +1173,7 @@ static void arcmsr_stop_hba_bgrb(struct CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_STOP_BGRB); if(!arcmsr_hba_wait_msgint_ready(acb)) { - printf("arcmsr%d: wait 'stop adapter rebulid' timeout \n" + printf("arcmsr%d: wait 'stop adapter background rebulid' timeout \n" , acb->pci_unit); } return; @@ -1079,7 +1188,7 @@ static void arcmsr_stop_hbb_bgrb(struct CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_MESSAGE_STOP_BGRB); if(!arcmsr_hbb_wait_msgint_ready(acb)) { - printf( "arcmsr%d: wait 'stop adapter rebulid' timeout \n" + printf( "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" , acb->pci_unit); } return; @@ -1088,6 +1197,20 @@ static void arcmsr_stop_hbb_bgrb(struct ************************************************************************ ************************************************************************ */ +static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *acb) +{ + acb->acb_flags &=~ACB_F_MSG_START_BGRB; + CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_STOP_BGRB); + CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell,ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE); + if(!arcmsr_hbc_wait_msgint_ready(acb)) { + printf("arcmsr%d: wait 'stop adapter background rebulid' timeout \n", acb->pci_unit); + } + return; +} +/* +************************************************************************ +************************************************************************ +*/ static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { @@ -1099,6 +1222,10 @@ static void arcmsr_stop_adapter_bgrb(str arcmsr_stop_hbb_bgrb(acb); } break; + case ACB_ADAPTER_TYPE_C: { + arcmsr_stop_hbc_bgrb(acb); + } + break; } return; } @@ -1121,18 +1248,6 @@ static void arcmsr_poll(struct cam_sim * return; } /* -********************************************************************** -********************************************************************** -*/ -static void arcmsr_intr_handler(void *arg) -{ - struct AdapterControlBlock *acb=(struct AdapterControlBlock *)arg; - - ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); - arcmsr_interrupt(acb); - ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); -} -/* ************************************************************************** ************************************************************************** */ @@ -1210,6 +1325,187 @@ static void arcmsr_iop2drv_data_read_han } return; } + +static void arcmsr_rescanLun_cb(struct cam_periph *periph, union ccb *ccb) +{ +/* + if (ccb->ccb_h.status != CAM_REQ_CMP) + printf("arcmsr_rescanLun_cb: Rescan Target=%x, lun=%x, failure status=%x\n",ccb->ccb_h.target_id,ccb->ccb_h.target_lun,ccb->ccb_h.status); + else + printf("arcmsr_rescanLun_cb: Rescan lun successfully!\n"); +*/ + xpt_free_path(ccb->ccb_h.path); + xpt_free_ccb(ccb); +} + +static void arcmsr_rescan_lun(struct AdapterControlBlock *acb, int target, int lun) +{ + struct cam_path *path; + union ccb *ccb; + + if ((ccb = (union ccb *)xpt_alloc_ccb_nowait()) == NULL) + return; + if (xpt_create_path(&path, xpt_periph, cam_sim_path(acb->psim), target, lun) != CAM_REQ_CMP) + { + xpt_free_ccb(ccb); + return; + } +/* printf("arcmsr_rescan_lun: Rescan Target=%x, Lun=%x\n", target, lun); */ + bzero(ccb, sizeof(union ccb)); + xpt_setup_ccb(&ccb->ccb_h, path, 5); + ccb->ccb_h.func_code = XPT_SCAN_LUN; + ccb->ccb_h.cbfcnp = arcmsr_rescanLun_cb; + ccb->crcn.flags = CAM_FLAG_NONE; + xpt_action(ccb); + return; +} + + +static void arcmsr_abort_dr_ccbs(struct AdapterControlBlock *acb, int target, int lun) +{ + struct CommandControlBlock *srb; + u_int32_t intmask_org; + int i; + + ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); + /* disable all outbound interrupts */ + intmask_org = arcmsr_disable_allintr(acb); + for (i = 0; i < ARCMSR_MAX_FREESRB_NUM; i++) + { + srb = acb->psrb_pool[i]; + if (srb->startdone == ARCMSR_SRB_START) + { + if((target == srb->pccb->ccb_h.target_id) && (lun == srb->pccb->ccb_h.target_lun)) + { + srb->startdone = ARCMSR_SRB_ABORTED; + srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; + arcmsr_srb_complete(srb, 1); + } + } + } + /* enable outbound Post Queue, outbound doorbell Interrupt */ + arcmsr_enable_allintr(acb, intmask_org); + ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); +} + + +/* +************************************************************************** +************************************************************************** +*/ +static void arcmsr_dr_handle(struct AdapterControlBlock *acb) { + u_int32_t devicemap; + u_int32_t target, lun; + u_int32_t deviceMapCurrent[4]={0}; + u_int8_t *pDevMap; + + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: + devicemap = offsetof(struct HBA_MessageUnit, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]); + for (target= 0; target < 4; target++) + { + deviceMapCurrent[target]=bus_space_read_4(acb->btag[0], acb->bhandle[0], devicemap); + devicemap += 4; + } + break; + + case ACB_ADAPTER_TYPE_B: + devicemap = offsetof(struct HBB_RWBUFFER, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]); + for (target= 0; target < 4; target++) + { + deviceMapCurrent[target]=bus_space_read_4(acb->btag[1], acb->bhandle[1], devicemap); + devicemap += 4; + } + break; + + case ACB_ADAPTER_TYPE_C: + devicemap = offsetof(struct HBC_MessageUnit, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]); + for (target= 0; target < 4; target++) + { + deviceMapCurrent[target]=bus_space_read_4(acb->btag[0], acb->bhandle[0], devicemap); + devicemap += 4; + } + break; + } + if(acb->acb_flags & ACB_F_BUS_HANG_ON) + { + acb->acb_flags &= ~ACB_F_BUS_HANG_ON; + } + /* + ** adapter posted CONFIG message + ** copy the new map, note if there are differences with the current map + */ + pDevMap = (u_int8_t *)&deviceMapCurrent[0]; + for (target= 0; target < ARCMSR_MAX_TARGETID - 1; target++) + { + if (*pDevMap != acb->device_map[target]) + { + u_int8_t difference, bit_check; + + difference= *pDevMap ^ acb->device_map[target]; + for(lun=0; lun < ARCMSR_MAX_TARGETLUN; lun++) + { + bit_check=(1 << lun); /*check bit from 0....31*/ + if(difference & bit_check) + { + if(acb->device_map[target] & bit_check) + {/* unit departed */ + printf("arcmsr_dr_handle: Target=%x, lun=%x, GONE!!!\n",target,lun); + arcmsr_abort_dr_ccbs(acb, target, lun); + arcmsr_rescan_lun(acb, target, lun); + acb->devstate[target][lun] = ARECA_RAID_GONE; + } + else + {/* unit arrived */ + printf("arcmsr_dr_handle: Target=%x, lun=%x, ARRIVING!!!\n",target,lun); + arcmsr_rescan_lun(acb, target, lun); + acb->devstate[target][lun] = ARECA_RAID_GOOD; + } + } + } +/* printf("arcmsr_dr_handle: acb->device_map[%x]=0x%x, deviceMapCurrent[%x]=%x\n",target,acb->device_map[target],target,*pDevMap); */ + acb->device_map[target]= *pDevMap; + } + pDevMap++; + } +} +/* +************************************************************************** +************************************************************************** +*/ +static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb) { + u_int32_t outbound_message; + + CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, ARCMSR_MU_OUTBOUND_MESSAGE0_INT); + outbound_message = CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[0]); + if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG) + arcmsr_dr_handle( acb ); +} +/* +************************************************************************** +************************************************************************** +*/ +static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb) { + u_int32_t outbound_message; + + /* clear interrupts */ + CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell, ARCMSR_MESSAGE_INT_CLEAR_PATTERN); + outbound_message = CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[0]); + if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG) + arcmsr_dr_handle( acb ); +} +/* +************************************************************************** +************************************************************************** +*/ +static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb) { + u_int32_t outbound_message; + + CHIP_REG_WRITE32(HBC_MessageUnit, 0, outbound_doorbell_clear, ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR); + outbound_message = CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[0]); + if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG) + arcmsr_dr_handle( acb ); +} /* ************************************************************************** ************************************************************************** @@ -1241,9 +1537,38 @@ static void arcmsr_hba_doorbell_isr(stru ************************************************************************** ************************************************************************** */ +static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *acb) +{ + u_int32_t outbound_doorbell; + + /* + ******************************************************************* + ** Maybe here we need to check wrqbuffer_lock is lock or not + ** DOORBELL: din! don! + ** check if there are any mail need to pack from firmware + ******************************************************************* + */ + outbound_doorbell=CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_doorbell); + CHIP_REG_WRITE32(HBC_MessageUnit, 0, outbound_doorbell_clear, outbound_doorbell); /* clear doorbell interrupt */ + if(outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) { + arcmsr_iop2drv_data_wrote_handle(acb); + } + if(outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) { + arcmsr_iop2drv_data_read_handle(acb); + } + if(outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { + arcmsr_hbc_message_isr(acb); /* messenger of "driver to iop commands" */ + } + return; +} +/* +************************************************************************** +************************************************************************** +*/ static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) { u_int32_t flag_srb; + u_int16_t error; /* ***************************************************************************** @@ -1255,7 +1580,8 @@ static void arcmsr_hba_postqueue_isr(str while((flag_srb=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_queueport)) != 0xFFFFFFFF) { /* check if command done with no error*/ - arcmsr_drain_donequeue(acb, flag_srb); + error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE; + arcmsr_drain_donequeue(acb, flag_srb, error); } /*drain reply FIFO*/ return; } @@ -1268,6 +1594,7 @@ static void arcmsr_hbb_postqueue_isr(str struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; u_int32_t flag_srb; int index; + u_int16_t error; /* ***************************************************************************** @@ -1283,7 +1610,38 @@ static void arcmsr_hbb_postqueue_isr(str index %= ARCMSR_MAX_HBB_POSTQUEUE; /*if last index number set it to 0 */ phbbmu->doneq_index=index; /* check if command done with no error*/ - arcmsr_drain_donequeue(acb, flag_srb); + error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE; + arcmsr_drain_donequeue(acb, flag_srb, error); + } /*drain reply FIFO*/ + return; +} +/* +************************************************************************** +************************************************************************** +*/ +static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb) +{ + u_int32_t flag_srb,throttling=0; + u_int16_t error; + + /* + ***************************************************************************** + ** areca cdb command done + ***************************************************************************** + */ + bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); + + while(CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) { + + flag_srb=CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_queueport_low); + /* check if command done with no error*/ + error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1)?TRUE:FALSE; + arcmsr_drain_donequeue(acb, flag_srb, error); + if(throttling==ARCMSR_HBC_ISR_THROTTLING_LEVEL) { + CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell,ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING); + break; + } + throttling++; } /*drain reply FIFO*/ return; } @@ -1299,14 +1657,12 @@ static void arcmsr_handle_hba_isr( struc ** check outbound intstatus ********************************************* */ - outbound_intstatus=CHIP_REG_READ32(HBA_MessageUnit, - 0, outbound_intstatus) & acb->outbound_int_enable; + outbound_intstatus=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intstatus) & acb->outbound_int_enable; if(!outbound_intstatus) { /*it must be share irq*/ return; } - CHIP_REG_WRITE32(HBA_MessageUnit, - 0, outbound_intstatus, outbound_intstatus);/*clear interrupt*/ + CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, outbound_intstatus);/*clear interrupt*/ /* MU doorbell interrupts*/ if(outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { arcmsr_hba_doorbell_isr(acb); @@ -1315,6 +1671,9 @@ static void arcmsr_handle_hba_isr( struc if(outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { arcmsr_hba_postqueue_isr(acb); } + if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { + arcmsr_hba_message_isr(acb); + } return; } /* @@ -1348,6 +1707,36 @@ static void arcmsr_handle_hbb_isr( struc if(outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) { *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007211850.o6LIoON6007938>