Index: head/sys/dev/ips/ips.c =================================================================== --- head/sys/dev/ips/ips.c (revision 152918) +++ head/sys/dev/ips/ips.c (revision 152919) @@ -1,746 +1,747 @@ /*- * Written by: David Jeffery * Copyright (c) 2002 Adaptec Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); +#include #include #include #include #include static d_open_t ips_open; static d_close_t ips_close; static d_ioctl_t ips_ioctl; MALLOC_DEFINE(M_IPSBUF, "ipsbuf","IPS driver buffer"); static struct cdevsw ips_cdevsw = { .d_version = D_VERSION, .d_flags = D_NEEDGIANT, .d_open = ips_open, .d_close = ips_close, .d_ioctl = ips_ioctl, .d_name = "ips", }; static const char* ips_adapter_name[] = { "N/A", "ServeRAID (copperhead)", "ServeRAID II (copperhead refresh)", "ServeRAID onboard (copperhead)", "ServeRAID onboard (copperhead)", "ServeRAID 3H (clarinet)", "ServeRAID 3L (clarinet lite)", "ServeRAID 4H (trombone)", "ServeRAID 4M (morpheus)", "ServeRAID 4L (morpheus lite)", "ServeRAID 4Mx (neo)", "ServeRAID 4Lx (neo lite)", "ServeRAID 5i II (sarasota)", "ServeRAID 5i (sarasota)", "ServeRAID 6M (marco)", "ServeRAID 6i (sebring)" }; static int ips_open(struct cdev *dev, int flags, int fmt, struct thread *td) { ips_softc_t *sc = dev->si_drv1; sc->state |= IPS_DEV_OPEN; return 0; } static int ips_close(struct cdev *dev, int flags, int fmt, struct thread *td) { ips_softc_t *sc = dev->si_drv1; sc->state &= ~IPS_DEV_OPEN; return 0; } static int ips_ioctl(struct cdev *dev, u_long command, caddr_t addr, int32_t flags, struct thread *td) { ips_softc_t *sc; sc = dev->si_drv1; return ips_ioctl_request(sc, command, addr, flags); } static void ips_cmd_dmaload(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) { ips_command_t *command = cmdptr; PRINTF(10, "ips: in ips_cmd_dmaload\n"); if(!error) command->command_phys_addr = segments[0].ds_addr; } /* is locking needed? what locking guarentees are there on removal? */ static int ips_cmdqueue_free(ips_softc_t *sc) { int i, error = -1; ips_command_t *command; if(!sc->used_commands){ for(i = 0; i < sc->max_cmds; i++){ command = &sc->commandarray[i]; if(command->command_phys_addr == 0) continue; bus_dmamap_unload(sc->command_dmatag, command->command_dmamap); bus_dmamem_free(sc->command_dmatag, command->command_buffer, command->command_dmamap); if (command->data_dmamap != NULL) bus_dmamap_destroy(command->data_dmatag, command->data_dmamap); } error = 0; sc->state |= IPS_OFFLINE; } sc->staticcmd = NULL; free(sc->commandarray, M_DEVBUF); return error; } /* places all ips command structs on the free command queue. No locking as if someone else tries * to access this during init, we have bigger problems */ static int ips_cmdqueue_init(ips_softc_t *sc) { int i; ips_command_t *command; sc->commandarray = (ips_command_t *)malloc(sizeof(ips_command_t) * sc->max_cmds, M_DEVBUF, M_NOWAIT|M_ZERO); if (sc->commandarray == NULL) return (ENOMEM); SLIST_INIT(&sc->free_cmd_list); for(i = 0; i < sc->max_cmds; i++){ command = &sc->commandarray[i]; command->id = i; command->sc = sc; if(bus_dmamem_alloc(sc->command_dmatag,&command->command_buffer, BUS_DMA_NOWAIT, &command->command_dmamap)) goto error; bus_dmamap_load(sc->command_dmatag, command->command_dmamap, command->command_buffer,IPS_COMMAND_LEN, ips_cmd_dmaload, command, BUS_DMA_NOWAIT); if(!command->command_phys_addr){ bus_dmamem_free(sc->command_dmatag, command->command_buffer, command->command_dmamap); goto error; } if (i != 0) { command->data_dmatag = sc->sg_dmatag; if (bus_dmamap_create(command->data_dmatag, 0, &command->data_dmamap)) goto error; SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next); } else sc->staticcmd = command; } sc->state &= ~IPS_OFFLINE; return 0; error: ips_cmdqueue_free(sc); return ENOMEM; } /* returns a free command struct if one is available. * It also blanks out anything that may be a wild pointer/value. * Also, command buffers are not freed. They are * small so they are saved and kept dmamapped and loaded. */ int ips_get_free_cmd(ips_softc_t *sc, ips_command_t **cmd, unsigned long flags) { ips_command_t *command; if(sc->state & IPS_OFFLINE){ return EIO; } if ((flags & IPS_STATIC_FLAG) == 0) { command = SLIST_FIRST(&sc->free_cmd_list); if(!command || (sc->state & IPS_TIMEOUT)){ return EBUSY; } SLIST_REMOVE_HEAD(&sc->free_cmd_list, next); (sc->used_commands)++; } else { if (sc->state & IPS_STATIC_BUSY) return EAGAIN; command = sc->staticcmd; sc->state |= IPS_STATIC_BUSY; } clear_ips_command(command); bzero(command->command_buffer, IPS_COMMAND_LEN); *cmd = command; return 0; } /* adds a command back to the free command queue */ void ips_insert_free_cmd(ips_softc_t *sc, ips_command_t *command) { if (sema_value(&sc->cmd_sema) != 0) panic("ips: command returned non-zero semaphore"); if (command != sc->staticcmd) { SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next); (sc->used_commands)--; } else { sc->state &= ~IPS_STATIC_BUSY; } } static const char* ips_diskdev_statename(u_int8_t state) { static char statebuf[20]; switch(state){ case IPS_LD_OFFLINE: return("OFFLINE"); break; case IPS_LD_OKAY: return("OK"); break; case IPS_LD_DEGRADED: return("DEGRADED"); break; case IPS_LD_FREE: return("FREE"); break; case IPS_LD_SYS: return("SYS"); break; case IPS_LD_CRS: return("CRS"); break; } sprintf(statebuf,"UNKNOWN(0x%02x)", state); return(statebuf); } static int ips_diskdev_init(ips_softc_t *sc) { int i; for(i=0; i < IPS_MAX_NUM_DRIVES; i++){ if(sc->drives[i].state == IPS_LD_FREE) continue; device_printf(sc->dev, "Logical Drive %d: RAID%d sectors: %u, state %s\n", i, sc->drives[i].raid_lvl, sc->drives[i].sector_count, ips_diskdev_statename(sc->drives[i].state)); if(sc->drives[i].state == IPS_LD_OKAY || sc->drives[i].state == IPS_LD_DEGRADED){ sc->diskdev[i] = device_add_child(sc->dev, NULL, -1); device_set_ivars(sc->diskdev[i],(void *)(uintptr_t) i); } } if(bus_generic_attach(sc->dev)){ device_printf(sc->dev, "Attaching bus failed\n"); } return 0; } static int ips_diskdev_free(ips_softc_t *sc) { int i; int error = 0; for(i = 0; i < IPS_MAX_NUM_DRIVES; i++){ if(sc->diskdev[i]) error = device_delete_child(sc->dev, sc->diskdev[i]); if(error) return error; } bus_generic_detach(sc->dev); return 0; } /* ips_timeout is periodically called to make sure no commands sent * to the card have become stuck. If it finds a stuck command, it * sets a flag so the driver won't start any more commands and then * is periodically called to see if all outstanding commands have * either finished or timed out. Once timed out, an attempt to * reinitialize the card is made. If that fails, the driver gives * up and declares the card dead. */ static void ips_timeout(void *arg) { ips_softc_t *sc = arg; int i, state = 0; ips_command_t *command; mtx_lock(&sc->queue_mtx); command = &sc->commandarray[0]; for(i = 0; i < sc->max_cmds; i++){ if(!command[i].timeout){ continue; } command[i].timeout--; if(!command[i].timeout){ if(!(sc->state & IPS_TIMEOUT)){ sc->state |= IPS_TIMEOUT; device_printf(sc->dev, "WARNING: command timeout. Adapter is in toaster mode, resetting to known state\n"); } ips_set_error(&command[i], ETIMEDOUT); command[i].callback(&command[i]); /* hmm, this should be enough cleanup */ } else state = 1; } if(!state && (sc->state & IPS_TIMEOUT)){ if(sc->ips_adapter_reinit(sc, 1)){ device_printf(sc->dev, "AIEE! adapter reset failed, giving up and going home! Have a nice day.\n"); sc->state |= IPS_OFFLINE; sc->state &= ~IPS_TIMEOUT; /* Grr, I hate this solution. I run waiting commands one at a time and error them out just before they would go to the card. This sucks. */ } else sc->state &= ~IPS_TIMEOUT; } if (sc->state != IPS_OFFLINE) sc->timer = timeout(ips_timeout, sc, 10*hz); mtx_unlock(&sc->queue_mtx); } /* check card and initialize it */ int ips_adapter_init(ips_softc_t *sc) { int i; DEVICE_PRINTF(1,sc->dev, "initializing\n"); if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, /* alignemnt */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ IPS_COMMAND_LEN + IPS_MAX_SG_LEN, /* numsegs */ 1, /* maxsegsize*/ IPS_COMMAND_LEN + IPS_MAX_SG_LEN, /* flags */ 0, /* lockfunc */ NULL, /* lockarg */ NULL, &sc->command_dmatag) != 0) { device_printf(sc->dev, "can't alloc command dma tag\n"); goto error; } if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, /* alignemnt */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ IPS_MAX_IOBUF_SIZE, /* numsegs */ IPS_MAX_SG_ELEMENTS, /* maxsegsize*/ IPS_MAX_IOBUF_SIZE, /* flags */ 0, /* lockfunc */ busdma_lock_mutex, /* lockarg */ &sc->queue_mtx, &sc->sg_dmatag) != 0) { device_printf(sc->dev, "can't alloc SG dma tag\n"); goto error; } /* create one command buffer until we know how many commands this card can handle */ sc->max_cmds = 1; ips_cmdqueue_init(sc); callout_handle_init(&sc->timer); if(sc->ips_adapter_reinit(sc, 0)) goto error; /* initialize ffdc values */ microtime(&sc->ffdc_resettime); sc->ffdc_resetcount = 1; if ((i = ips_ffdc_reset(sc)) != 0) { device_printf(sc->dev, "failed to send ffdc reset to device (%d)\n", i); goto error; } if ((i = ips_get_adapter_info(sc)) != 0) { device_printf(sc->dev, "failed to get adapter configuration data from device (%d)\n", i); goto error; } ips_update_nvram(sc); /* no error check as failure doesn't matter */ if(sc->adapter_type > 0 && sc->adapter_type <= IPS_ADAPTER_MAX_T){ device_printf(sc->dev, "adapter type: %s\n", ips_adapter_name[sc->adapter_type]); } if ((i = ips_get_drive_info(sc)) != 0) { device_printf(sc->dev, "failed to get drive configuration data from device (%d)\n", i); goto error; } ips_cmdqueue_free(sc); if(sc->adapter_info.max_concurrent_cmds) sc->max_cmds = min(128, sc->adapter_info.max_concurrent_cmds); else sc->max_cmds = 32; if(ips_cmdqueue_init(sc)){ device_printf(sc->dev, "failed to initialize command buffers\n"); goto error; } sc->device_file = make_dev(&ips_cdevsw, device_get_unit(sc->dev), UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, "ips%d", device_get_unit(sc->dev)); sc->device_file->si_drv1 = sc; ips_diskdev_init(sc); sc->timer = timeout(ips_timeout, sc, 10*hz); return 0; error: ips_adapter_free(sc); return ENXIO; } /* see if we should reinitialize the card and wait for it to timeout or complete initialization */ int ips_morpheus_reinit(ips_softc_t *sc, int force) { u_int32_t tmp; int i; tmp = ips_read_4(sc, MORPHEUS_REG_OISR); if(!force && (ips_read_4(sc, MORPHEUS_REG_OMR0) >= IPS_POST1_OK) && (ips_read_4(sc, MORPHEUS_REG_OMR1) != 0xdeadbeef) && !tmp){ ips_write_4(sc, MORPHEUS_REG_OIMR, 0); return 0; } ips_write_4(sc, MORPHEUS_REG_OIMR, 0xff); ips_read_4(sc, MORPHEUS_REG_OIMR); device_printf(sc->dev, "resetting adapter, this may take up to 5 minutes\n"); ips_write_4(sc, MORPHEUS_REG_IDR, 0x80000000); DELAY(5000000); - pci_read_config(sc->dev, 0, 4); + ips_read_4(sc, MORPHEUS_REG_OIMR); tmp = ips_read_4(sc, MORPHEUS_REG_OISR); for(i = 0; i < 45 && !(tmp & MORPHEUS_BIT_POST1); i++){ DELAY(1000000); DEVICE_PRINTF(2, sc->dev, "post1: %d\n", i); tmp = ips_read_4(sc, MORPHEUS_REG_OISR); } if(tmp & MORPHEUS_BIT_POST1) ips_write_4(sc, MORPHEUS_REG_OISR, MORPHEUS_BIT_POST1); if( i == 45 || ips_read_4(sc, MORPHEUS_REG_OMR0) < IPS_POST1_OK){ device_printf(sc->dev,"Adapter error during initialization.\n"); return 1; } for(i = 0; i < 240 && !(tmp & MORPHEUS_BIT_POST2); i++){ DELAY(1000000); DEVICE_PRINTF(2, sc->dev, "post2: %d\n", i); tmp = ips_read_4(sc, MORPHEUS_REG_OISR); } if(tmp & MORPHEUS_BIT_POST2) ips_write_4(sc, MORPHEUS_REG_OISR, MORPHEUS_BIT_POST2); if(i == 240 || !ips_read_4(sc, MORPHEUS_REG_OMR1)){ device_printf(sc->dev, "adapter failed config check\n"); return 1; } ips_write_4(sc, MORPHEUS_REG_OIMR, 0); if(force && ips_clear_adapter(sc)){ device_printf(sc->dev, "adapter clear failed\n"); return 1; } return 0; } /* clean up so we can unload the driver. */ int ips_adapter_free(ips_softc_t *sc) { int error = 0; if(sc->state & IPS_DEV_OPEN) return EBUSY; if((error = ips_diskdev_free(sc))) return error; if(ips_cmdqueue_free(sc)){ device_printf(sc->dev, "trying to exit when command queue is not empty!\n"); return EBUSY; } DEVICE_PRINTF(1, sc->dev, "free\n"); untimeout(ips_timeout, sc, sc->timer); if(sc->sg_dmatag) bus_dma_tag_destroy(sc->sg_dmatag); if(sc->command_dmatag) bus_dma_tag_destroy(sc->command_dmatag); if(sc->device_file) destroy_dev(sc->device_file); return 0; } static __inline int ips_morpheus_check_intr(ips_softc_t *sc) { int cmdnumber; ips_cmd_status_t status; ips_command_t *command; int found = 0; u_int32_t oisr; oisr = ips_read_4(sc, MORPHEUS_REG_OISR); PRINTF(9, "interrupt registers out:%x\n", oisr); if(!(oisr & MORPHEUS_BIT_CMD_IRQ)){ DEVICE_PRINTF(2,sc->dev, "got a non-command irq\n"); return (0); } while((status.value = ips_read_4(sc, MORPHEUS_REG_OQPR)) != 0xffffffff){ cmdnumber = status.fields.command_id; command = &sc->commandarray[cmdnumber]; command->status.value = status.value; command->timeout = 0; command->callback(command); found = 1; } return (found); } void ips_morpheus_intr(void *void_sc) { ips_softc_t *sc = void_sc; mtx_lock(&sc->queue_mtx); ips_morpheus_check_intr(sc); mtx_unlock(&sc->queue_mtx); } void ips_morpheus_poll(ips_command_t *command) { uint32_t ts; /* * Locks are not used here because this is only called during * crashdumps. */ ts = time_second + command->timeout; while ((command->timeout != 0) && (ips_morpheus_check_intr(command->sc) == 0) && (ts > time_second)) DELAY(1000); } void ips_issue_morpheus_cmd(ips_command_t *command) { /* hmmm, is there a cleaner way to do this? */ if(command->sc->state & IPS_OFFLINE){ ips_set_error(command, EINVAL); command->callback(command); return; } command->timeout = 10; ips_write_4(command->sc, MORPHEUS_REG_IQPR, command->command_phys_addr); } static void ips_copperhead_queue_callback(void *queueptr, bus_dma_segment_t *segments,int segnum, int error) { ips_copper_queue_t *queue = queueptr; if(error){ return; } queue->base_phys_addr = segments[0].ds_addr; } static int ips_copperhead_queue_init(ips_softc_t *sc) { int error; bus_dma_tag_t dmatag; bus_dmamap_t dmamap; if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, /* alignemnt */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ sizeof(ips_copper_queue_t), /* numsegs */ 1, /* maxsegsize*/ sizeof(ips_copper_queue_t), /* flags */ 0, /* lockfunc */ NULL, /* lockarg */ NULL, &dmatag) != 0) { device_printf(sc->dev, "can't alloc dma tag for statue queue\n"); error = ENOMEM; goto exit; } if(bus_dmamem_alloc(dmatag, (void *)&(sc->copper_queue), BUS_DMA_NOWAIT, &dmamap)){ error = ENOMEM; goto exit; } bzero(sc->copper_queue, sizeof(ips_copper_queue_t)); sc->copper_queue->dmatag = dmatag; sc->copper_queue->dmamap = dmamap; sc->copper_queue->nextstatus = 1; bus_dmamap_load(dmatag, dmamap, &(sc->copper_queue->status[0]), IPS_MAX_CMD_NUM * 4, ips_copperhead_queue_callback, sc->copper_queue, BUS_DMA_NOWAIT); if(sc->copper_queue->base_phys_addr == 0){ error = ENOMEM; goto exit; } ips_write_4(sc, COPPER_REG_SQSR, sc->copper_queue->base_phys_addr); ips_write_4(sc, COPPER_REG_SQER, sc->copper_queue->base_phys_addr + IPS_MAX_CMD_NUM * 4); ips_write_4(sc, COPPER_REG_SQHR, sc->copper_queue->base_phys_addr + 4); ips_write_4(sc, COPPER_REG_SQTR, sc->copper_queue->base_phys_addr); return 0; exit: bus_dmamem_free(dmatag, sc->copper_queue, dmamap); bus_dma_tag_destroy(dmatag); return error; } /* see if we should reinitialize the card and wait for it to timeout or complete initialization FIXME */ int ips_copperhead_reinit(ips_softc_t *sc, int force) { int i, j; u_int32_t postcode = 0, configstatus = 0; ips_write_1(sc, COPPER_REG_SCPR, 0x80); ips_write_1(sc, COPPER_REG_SCPR, 0); device_printf(sc->dev, "reinitializing adapter, this could take several minutes.\n"); for(j = 0; j < 2; j++){ postcode <<= 8; for(i = 0; i < 45; i++){ if(ips_read_1(sc, COPPER_REG_HISR) & COPPER_GHI_BIT){ postcode |= ips_read_1(sc, COPPER_REG_ISPR); ips_write_1(sc, COPPER_REG_HISR, COPPER_GHI_BIT); break; } else DELAY(1000000); } if(i == 45) return 1; } for(j = 0; j < 2; j++){ configstatus <<= 8; for(i = 0; i < 240; i++){ if(ips_read_1(sc, COPPER_REG_HISR) & COPPER_GHI_BIT){ configstatus |= ips_read_1(sc, COPPER_REG_ISPR); ips_write_1(sc, COPPER_REG_HISR, COPPER_GHI_BIT); break; } else DELAY(1000000); } if(i == 240) return 1; } for(i = 0; i < 240; i++){ if(!(ips_read_1(sc, COPPER_REG_CBSP) & COPPER_OP_BIT)){ break; } else DELAY(1000000); } if(i == 240) return 1; ips_write_2(sc, COPPER_REG_CCCR, 0x1000 | COPPER_ILE_BIT); ips_write_1(sc, COPPER_REG_SCPR, COPPER_EBM_BIT); ips_copperhead_queue_init(sc); ips_write_1(sc, COPPER_REG_HISR, COPPER_GHI_BIT); i = ips_read_1(sc, COPPER_REG_SCPR); ips_write_1(sc, COPPER_REG_HISR, COPPER_EI_BIT); if(!configstatus){ device_printf(sc->dev, "adapter initialization failed\n"); return 1; } if(force && ips_clear_adapter(sc)){ device_printf(sc->dev, "adapter clear failed\n"); return 1; } return 0; } static u_int32_t ips_copperhead_cmd_status(ips_softc_t *sc) { u_int32_t value; int statnum = sc->copper_queue->nextstatus++; if(sc->copper_queue->nextstatus == IPS_MAX_CMD_NUM) sc->copper_queue->nextstatus = 0; value = sc->copper_queue->status[statnum]; ips_write_4(sc, COPPER_REG_SQTR, sc->copper_queue->base_phys_addr + 4 * statnum); return value; } void ips_copperhead_intr(void *void_sc) { ips_softc_t *sc = (ips_softc_t *)void_sc; int cmdnumber; ips_cmd_status_t status; mtx_lock(&sc->queue_mtx); while(ips_read_1(sc, COPPER_REG_HISR) & COPPER_SCE_BIT){ status.value = ips_copperhead_cmd_status(sc); cmdnumber = status.fields.command_id; sc->commandarray[cmdnumber].status.value = status.value; sc->commandarray[cmdnumber].timeout = 0; sc->commandarray[cmdnumber].callback(&(sc->commandarray[cmdnumber])); PRINTF(9, "ips: got command %d\n", cmdnumber); } mtx_unlock(&sc->queue_mtx); return; } void ips_issue_copperhead_cmd(ips_command_t *command) { int i; /* hmmm, is there a cleaner way to do this? */ if(command->sc->state & IPS_OFFLINE){ ips_set_error(command, EINVAL); command->callback(command); return; } command->timeout = 10; for(i = 0; ips_read_4(command->sc, COPPER_REG_CCCR) & COPPER_SEM_BIT; i++ ){ if( i == 20){ printf("sem bit still set, can't send a command\n"); return; } DELAY(500);/* need to do a delay here */ } ips_write_4(command->sc, COPPER_REG_CCSAR, command->command_phys_addr); ips_write_2(command->sc, COPPER_REG_CCCR, COPPER_CMD_START); } void ips_copperhead_poll(ips_command_t *command) { printf("ips: cmd polling not implemented for copperhead devices\n"); } Index: head/sys/dev/ips/ips.h =================================================================== --- head/sys/dev/ips/ips.h (revision 152918) +++ head/sys/dev/ips/ips.h (revision 152919) @@ -1,491 +1,188 @@ /*- * Copyright (c) 2002 Adaptec Inc. * All rights reserved. * * Written by: David Jeffery * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ +#ifndef _IPS_H +#define _IPS_H +#ifdef _KERNEL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include -#include - MALLOC_DECLARE(M_IPSBUF); /* - * IPS CONSTANTS - */ -#define IPS_VENDOR_ID 0x1014 -#define IPS_VENDOR_ID_ADAPTEC 0x9005 -#define IPS_MORPHEUS_DEVICE_ID 0x01BD -#define IPS_COPPERHEAD_DEVICE_ID 0x002E -#define IPS_MARCO_DEVICE_ID 0x0250 -#define IPS_CSL 0xff -#define IPS_POCL 0x30 - -/* amounts of memory to allocate for certain commands */ -#define IPS_ADAPTER_INFO_LEN (sizeof(ips_adapter_info_t)) -#define IPS_DRIVE_INFO_LEN (sizeof(ips_drive_info_t)) -#define IPS_COMMAND_LEN 24 -#define IPS_MAX_SG_LEN (sizeof(ips_sg_element_t) * IPS_MAX_SG_ELEMENTS) -#define IPS_NVRAM_PAGE_SIZE 128 -/* various flags */ -#define IPS_STATIC_FLAG 0x01 - -/* states for the card to be in */ -#define IPS_DEV_OPEN 0x01 -#define IPS_TIMEOUT 0x02 /* command time out, need reset */ -#define IPS_OFFLINE 0x04 /* can't reset card/card failure */ -#define IPS_STATIC_BUSY 0x08 - -/* max number of commands set to something low for now */ -#define IPS_MAX_CMD_NUM 128 -#define IPS_MAX_NUM_DRIVES 8 -#define IPS_MAX_SG_ELEMENTS 32 -#define IPS_MAX_IOBUF_SIZE (64 * 1024) -#define IPS_BLKSIZE 512 - -/* logical drive states */ - -#define IPS_LD_OFFLINE 0x02 -#define IPS_LD_OKAY 0x03 -#define IPS_LD_DEGRADED 0x04 -#define IPS_LD_FREE 0x00 -#define IPS_LD_SYS 0x06 -#define IPS_LD_CRS 0x24 - -/* register offsets */ -#define MORPHEUS_REG_OMR0 0x0018 /* Outbound Msg. Reg. 0 */ -#define MORPHEUS_REG_OMR1 0x001C /* Outbound Msg. Reg. 1 */ -#define MORPHEUS_REG_IDR 0x0020 /* Inbound Doorbell Reg. */ -#define MORPHEUS_REG_IISR 0x0024 /* Inbound IRQ Status Reg. */ -#define MORPHEUS_REG_IIMR 0x0028 /* Inbound IRQ Mask Reg. */ -#define MORPHEUS_REG_OISR 0x0030 /* Outbound IRQ Status Reg. */ -#define MORPHEUS_REG_OIMR 0x0034 /* Outbound IRQ Status Reg. */ -#define MORPHEUS_REG_IQPR 0x0040 /* Inbound Queue Port Reg. */ -#define MORPHEUS_REG_OQPR 0x0044 /* Outbound Queue Port Reg. */ - -#define COPPER_REG_SCPR 0x05 /* Subsystem Ctrl. Port Reg. */ -#define COPPER_REG_ISPR 0x06 /* IRQ Status Port Reg. */ -#define COPPER_REG_CBSP 0x07 /* ? Reg. */ -#define COPPER_REG_HISR 0x08 /* Host IRQ Status Reg. */ -#define COPPER_REG_CCSAR 0x10 /* Cmd. Channel Sys Addr Reg.*/ -#define COPPER_REG_CCCR 0x14 /* Cmd. Channel Ctrl. Reg. */ -#define COPPER_REG_SQHR 0x20 /* Status Queue Head Reg. */ -#define COPPER_REG_SQTR 0x24 /* Status Queue Tail Reg. */ -#define COPPER_REG_SQER 0x28 /* Status Queue End Reg. */ -#define COPPER_REG_SQSR 0x2C /* Status Queue Start Reg. */ - -/* bit definitions */ -#define MORPHEUS_BIT_POST1 0x01 -#define MORPHEUS_BIT_POST2 0x02 -#define MORPHEUS_BIT_CMD_IRQ 0x08 - -#define COPPER_CMD_START 0x101A -#define COPPER_SEM_BIT 0x08 -#define COPPER_EI_BIT 0x80 -#define COPPER_EBM_BIT 0x02 -#define COPPER_RESET_BIT 0x80 -#define COPPER_GHI_BIT 0x04 -#define COPPER_SCE_BIT 0x01 -#define COPPER_OP_BIT 0x01 -#define COPPER_ILE_BIT 0x10 - -/* status defines */ -#define IPS_POST1_OK 0x8000 -#define IPS_POST2_OK 0x000f - -/* command op codes */ -#define IPS_READ_CMD 0x02 -#define IPS_WRITE_CMD 0x03 -#define IPS_ADAPTER_INFO_CMD 0x05 -#define IPS_CACHE_FLUSH_CMD 0x0A -#define IPS_REBUILD_STATUS_CMD 0x0C -#define IPS_ERROR_TABLE_CMD 0x17 -#define IPS_DRIVE_INFO_CMD 0x19 -#define IPS_SUBSYS_PARAM_CMD 0x40 -#define IPS_CONFIG_SYNC_CMD 0x58 -#define IPS_SG_READ_CMD 0x82 -#define IPS_SG_WRITE_CMD 0x83 -#define IPS_RW_NVRAM_CMD 0xBC -#define IPS_FFDC_CMD 0xD7 - -/* basic_status information returned by the adapter */ -#define IPS_MIN_ERROR 0x02 -#define IPS_BASIC_STATUS_MASK 0xFF -#define IPS_GSC_STATUS_MASK 0x0F -#define IPS_CMD_SUCCESS 0x00 -#define IPS_CMD_RECOVERED_ERROR 0x01 -#define IPS_DRV_ERROR 0x02 /* Driver supplied error */ -#define IPS_INVAL_OPCO 0x03 -#define IPS_INVAL_CMD_BLK 0x04 -#define IPS_INVAL_PARM_BLK 0x05 -#define IPS_BUSY 0x08 -#define IPS_CMD_CMPLT_WERROR 0x0C -#define IPS_LD_ERROR 0x0D -#define IPS_CMD_TIMEOUT 0x0E -#define IPS_PHYS_DRV_ERROR 0x0F - -/* extended_status information returned by the adapter */ -#define IPS_ERR_SEL_TO 0xF0 -#define IPS_ERR_OU_RUN 0xF2 -#define IPS_ERR_HOST_RESET 0xF7 -#define IPS_ERR_DEV_RESET 0xF8 -#define IPS_ERR_RECOVERY 0xFC -#define IPS_ERR_CKCOND 0xFF - -#define IPS_OS_FREEBSD 8 -#define IPS_VERSION_MAJOR "0.90" -#define IPS_VERSION_MINOR ".10" - -/* Adapter Types */ -#define IPS_ADAPTER_COPPERHEAD 0x01 -#define IPS_ADAPTER_COPPERHEAD2 0x02 -#define IPS_ADAPTER_COPPERHEADOB1 0x03 -#define IPS_ADAPTER_COPPERHEADOB2 0x04 -#define IPS_ADAPTER_CLARINET 0x05 -#define IPS_ADAPTER_CLARINETLITE 0x06 -#define IPS_ADAPTER_TROMBONE 0x07 -#define IPS_ADAPTER_MORPHEUS 0x08 -#define IPS_ADAPTER_MORPHEUSLITE 0x09 -#define IPS_ADAPTER_NEO 0x0A -#define IPS_ADAPTER_NEOLITE 0x0B -#define IPS_ADAPTER_SARASOTA2 0x0C -#define IPS_ADAPTER_SARASOTA1 0x0D -#define IPS_ADAPTER_MARCO 0x0E -#define IPS_ADAPTER_SEBRING 0x0F -#define IPS_ADAPTER_MAX_T IPS_ADAPTER_SEBRING - -/* values for ffdc_settime (from gmtime) */ -#define IPS_SECSPERMIN 60 -#define IPS_MINSPERHOUR 60 -#define IPS_HOURSPERDAY 24 -#define IPS_DAYSPERWEEK 7 -#define IPS_DAYSPERNYEAR 365 -#define IPS_DAYSPERLYEAR 366 -#define IPS_SECSPERHOUR (IPS_SECSPERMIN * IPS_MINSPERHOUR) -#define IPS_SECSPERDAY ((long) IPS_SECSPERHOUR * IPS_HOURSPERDAY) -#define IPS_MONSPERYEAR 12 -#define IPS_EPOCH_YEAR 1970 -#define IPS_LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) -#define ips_isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) - -/* * IPS MACROS */ #define ips_read_1(sc,offset) bus_space_read_1(sc->bustag, sc->bushandle, offset) #define ips_read_2(sc,offset) bus_space_read_2(sc->bustag, sc->bushandle, offset) #define ips_read_4(sc,offset) bus_space_read_4(sc->bustag, sc->bushandle, offset) #define ips_write_1(sc,offset,value) bus_space_write_1(sc->bustag, sc->bushandle, offset, value) #define ips_write_2(sc,offset,value) bus_space_write_2(sc->bustag, sc->bushandle, offset, value) #define ips_write_4(sc,offset,value) bus_space_write_4(sc->bustag, sc->bushandle, offset, value) /* this is ugly. It zeros the end elements in an ips_command_t struct starting with the status element */ #define clear_ips_command(command) bzero(&((command)->status), (unsigned long)(&(command)[1])-(unsigned long)&((command)->status)) #define ips_read_request(iobuf) ((iobuf)->bio_cmd == BIO_READ) #define COMMAND_ERROR(command) (((command)->status.fields.basic_status & IPS_GSC_STATUS_MASK) >= IPS_MIN_ERROR) #define ips_set_error(command, error) do { \ (command)->status.fields.basic_status = IPS_DRV_ERROR; \ (command)->status.fields.reserved = ((error) & 0x0f); \ } while (0); #ifndef IPS_DEBUG #define DEVICE_PRINTF(x...) #define PRINTF(x...) #else #define DEVICE_PRINTF(level,x...) if(IPS_DEBUG >= level)device_printf(x) #define PRINTF(level,x...) if(IPS_DEBUG >= level)printf(x) #endif -/* - * IPS STRUCTS - */ - struct ips_softc; -typedef struct{ - u_int8_t command; - u_int8_t id; - u_int8_t drivenum; - u_int8_t reserve2; - u_int32_t lba; - u_int32_t buffaddr; - u_int32_t reserve3; -} __attribute__ ((packed)) ips_generic_cmd; - -typedef struct{ - u_int8_t command; - u_int8_t id; - u_int8_t drivenum; - u_int8_t segnum; - u_int32_t lba; - u_int32_t buffaddr; - u_int16_t length; - u_int16_t reserve1; -} __attribute__ ((packed)) ips_io_cmd; - -typedef struct{ - u_int8_t command; - u_int8_t id; - u_int8_t pagenum; - u_int8_t rw; - u_int32_t reserve1; - u_int32_t buffaddr; - u_int32_t reserve3; -} __attribute__ ((packed)) ips_rw_nvram_cmd; - -typedef struct{ - u_int8_t command; - u_int8_t id; - u_int8_t drivenum; - u_int8_t reserve1; - u_int32_t reserve2; - u_int32_t buffaddr; - u_int32_t reserve3; -} __attribute__ ((packed)) ips_drive_cmd; - -typedef struct{ - u_int8_t command; - u_int8_t id; - u_int8_t reserve1; - u_int8_t commandtype; - u_int32_t reserve2; - u_int32_t buffaddr; - u_int32_t reserve3; -} __attribute__((packed)) ips_adapter_info_cmd; - -typedef struct{ - u_int8_t command; - u_int8_t id; - u_int8_t reset_count; - u_int8_t reset_type; - u_int8_t second; - u_int8_t minute; - u_int8_t hour; - u_int8_t day; - u_int8_t reserve1[4]; - u_int8_t month; - u_int8_t yearH; - u_int8_t yearL; - u_int8_t reserve2; -} __attribute__((packed)) ips_adapter_ffdc_cmd; - -typedef union{ - ips_generic_cmd generic_cmd; - ips_drive_cmd drive_cmd; - ips_adapter_info_cmd adapter_info_cmd; -} ips_cmd_buff_t; - typedef struct { - u_int32_t signature; - u_int8_t reserved; - u_int8_t adapter_slot; - u_int16_t adapter_type; - u_int8_t bios_high[4]; - u_int8_t bios_low[4]; - u_int16_t reserve2; - u_int8_t reserve3; - u_int8_t operating_system; - u_int8_t driver_high[4]; - u_int8_t driver_low[4]; - u_int8_t reserve4[100]; -}__attribute__((packed)) ips_nvram_page5; - -typedef struct{ - u_int32_t addr; - u_int32_t len; -} ips_sg_element_t; - -typedef struct{ - u_int8_t drivenum; - u_int8_t merge_id; - u_int8_t raid_lvl; - u_int8_t state; - u_int32_t sector_count; -} __attribute__((packed)) ips_drive_t; - -typedef struct{ - u_int8_t drivecount; - u_int8_t reserve1; - u_int16_t reserve2; - ips_drive_t drives[IPS_MAX_NUM_DRIVES]; -}__attribute__((packed)) ips_drive_info_t; - -typedef struct{ - u_int8_t drivecount; - u_int8_t miscflags; - u_int8_t SLTflags; - u_int8_t BSTflags; - u_int8_t pwr_chg_count; - u_int8_t wrong_addr_count; - u_int8_t unident_count; - u_int8_t nvram_dev_chg_count; - u_int8_t codeblock_version[8]; - u_int8_t bootblock_version[8]; - u_int32_t drive_sector_count[IPS_MAX_NUM_DRIVES]; - u_int8_t max_concurrent_cmds; - u_int8_t max_phys_devices; - u_int16_t flash_prog_count; - u_int8_t defunct_disks; - u_int8_t rebuildflags; - u_int8_t offline_drivecount; - u_int8_t critical_drivecount; - u_int16_t config_update_count; - u_int8_t blockedflags; - u_int8_t psdn_error; - u_int16_t addr_dead_disk[4*16];/* ugly, max # channels * max # scsi devices per channel */ -}__attribute__((packed)) ips_adapter_info_t; - -typedef struct { u_int32_t status[IPS_MAX_CMD_NUM]; u_int32_t base_phys_addr; int nextstatus; bus_dma_tag_t dmatag; bus_dmamap_t dmamap; } ips_copper_queue_t; -typedef union { - struct { - u_int8_t reserved; - u_int8_t command_id; - u_int8_t basic_status; - u_int8_t extended_status; - } fields; - volatile u_int32_t value; -} ips_cmd_status_t; - /* used to keep track of current commands to the card */ typedef struct ips_command{ u_int8_t command_number; u_int8_t id; u_int8_t timeout; struct ips_softc * sc; bus_dma_tag_t data_dmatag; bus_dmamap_t data_dmamap; bus_dmamap_t command_dmamap; void * command_buffer; u_int32_t command_phys_addr;/*WARNING! must be changed if 64bit addressing ever used*/ ips_cmd_status_t status; SLIST_ENTRY(ips_command) next; void * data_buffer; void * arg; void (* callback)(struct ips_command *command); }ips_command_t; typedef struct ips_softc{ struct resource * iores; struct resource * irqres; struct intr_config_hook ips_ich; int configured; int state; int iotype; int rid; int irqrid; void * irqcookie; bus_space_tag_t bustag; bus_space_handle_t bushandle; bus_dma_tag_t adapter_dmatag; bus_dma_tag_t command_dmatag; bus_dma_tag_t sg_dmatag; device_t dev; struct cdev *device_file; struct callout_handle timer; u_int16_t adapter_type; ips_adapter_info_t adapter_info; device_t diskdev[IPS_MAX_NUM_DRIVES]; ips_drive_t drives[IPS_MAX_NUM_DRIVES]; u_int8_t drivecount; u_int16_t ffdc_resetcount; struct timeval ffdc_resettime; u_int8_t next_drive; u_int8_t max_cmds; volatile u_int8_t used_commands; ips_command_t *commandarray; ips_command_t *staticcmd; SLIST_HEAD(command_list, ips_command) free_cmd_list; int (* ips_adapter_reinit)(struct ips_softc *sc, int force); void (* ips_adapter_intr)(void *sc); void (* ips_issue_cmd)(ips_command_t *command); void (* ips_poll_cmd)(ips_command_t *command); ips_copper_queue_t * copper_queue; struct mtx queue_mtx; struct bio_queue_head queue; struct sema cmd_sema; }ips_softc_t; /* function defines from ips_ioctl.c */ extern int ips_ioctl_request(ips_softc_t *sc, u_long ioctl_cmd, caddr_t addr, int32_t flags); /* function defines from ips_disk.c */ extern void ipsd_finish(struct bio *iobuf); /* function defines from ips_commands.c */ extern int ips_flush_cache(ips_softc_t *sc); extern void ips_start_io_request(ips_softc_t *sc); extern int ips_get_drive_info(ips_softc_t *sc); extern int ips_get_adapter_info(ips_softc_t *sc); extern int ips_ffdc_reset(ips_softc_t *sc); extern int ips_update_nvram(ips_softc_t *sc); extern int ips_clear_adapter(ips_softc_t *sc); /* function defines from ips.c */ extern int ips_get_free_cmd(ips_softc_t *sc, ips_command_t **command, unsigned long flags); extern void ips_insert_free_cmd(ips_softc_t *sc, ips_command_t *command); extern int ips_adapter_init(ips_softc_t *sc); extern int ips_morpheus_reinit(ips_softc_t *sc, int force); extern int ips_adapter_free(ips_softc_t *sc); extern void ips_morpheus_intr(void *sc); extern void ips_issue_morpheus_cmd(ips_command_t *command); extern void ips_morpheus_poll(ips_command_t *command); extern int ips_copperhead_reinit(ips_softc_t *sc, int force); extern void ips_copperhead_intr(void *sc); extern void ips_issue_copperhead_cmd(ips_command_t *command); extern void ips_copperhead_poll(ips_command_t *command); +#endif +#endif Index: head/sys/dev/ips/ips_commands.c =================================================================== --- head/sys/dev/ips/ips_commands.c (revision 152918) +++ head/sys/dev/ips/ips_commands.c (revision 152919) @@ -1,670 +1,671 @@ /*- * Written by: David Jeffery * Copyright (c) 2002 Adaptec Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); +#include #include /* * This is an interrupt callback. It is called from * interrupt context when the adapter has completed the * command. This very generic callback simply stores * the command's return value in command->arg and wake's * up anyone waiting on the command. */ static void ips_wakeup_callback(ips_command_t *command) { bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_POSTWRITE); sema_post(&command->sc->cmd_sema); } /* Below are a series of functions for sending an IO request * to the adapter. The flow order is: start, send, callback, finish. * The caller must have already assembled an iorequest struct to hold * the details of the IO request. */ static void ips_io_request_finish(ips_command_t *command) { struct bio *iobuf = command->arg; if(ips_read_request(iobuf)) { bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_POSTREAD); } else { bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_POSTWRITE); } bus_dmamap_unload(command->data_dmatag, command->data_dmamap); if(COMMAND_ERROR(command)){ iobuf->bio_flags |=BIO_ERROR; iobuf->bio_error = EIO; printf("ips: io error, status= 0x%x\n", command->status.value); } ips_insert_free_cmd(command->sc, command); ipsd_finish(iobuf); } static void ips_io_request_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) { ips_softc_t *sc; ips_command_t *command = cmdptr; ips_sg_element_t *sg_list; ips_io_cmd *command_struct; struct bio *iobuf = command->arg; int i, length = 0; u_int8_t cmdtype; sc = command->sc; if(error){ printf("ips: error = %d in ips_sg_request_callback\n", error); bus_dmamap_unload(command->data_dmatag, command->data_dmamap); iobuf->bio_flags |= BIO_ERROR; iobuf->bio_error = ENOMEM; ips_insert_free_cmd(sc, command); ipsd_finish(iobuf); return; } command_struct = (ips_io_cmd *)command->command_buffer; command_struct->id = command->id; command_struct->drivenum = (uintptr_t)iobuf->bio_driver1; if(segnum != 1){ if(ips_read_request(iobuf)) cmdtype = IPS_SG_READ_CMD; else cmdtype = IPS_SG_WRITE_CMD; command_struct->segnum = segnum; sg_list = (ips_sg_element_t *)((u_int8_t *) command->command_buffer + IPS_COMMAND_LEN); for(i = 0; i < segnum; i++){ sg_list[i].addr = segments[i].ds_addr; sg_list[i].len = segments[i].ds_len; length += segments[i].ds_len; } command_struct->buffaddr = (u_int32_t)command->command_phys_addr + IPS_COMMAND_LEN; } else { if(ips_read_request(iobuf)) cmdtype = IPS_READ_CMD; else cmdtype = IPS_WRITE_CMD; command_struct->buffaddr = segments[0].ds_addr; length = segments[0].ds_len; } command_struct->command = cmdtype; command_struct->lba = iobuf->bio_pblkno; length = (length + IPS_BLKSIZE - 1)/IPS_BLKSIZE; command_struct->length = length; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); if(ips_read_request(iobuf)) { bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_PREREAD); } else { bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_PREWRITE); } PRINTF(10, "ips test: command id: %d segments: %d " "pblkno: %lld length: %d, ds_len: %d\n", command->id, segnum, iobuf->bio_pblkno, length, segments[0].ds_len); sc->ips_issue_cmd(command); return; } static int ips_send_io_request(ips_command_t *command, struct bio *iobuf) { command->callback = ips_io_request_finish; command->arg = iobuf; PRINTF(10, "ips test: : bcount %ld\n", iobuf->bio_bcount); bus_dmamap_load(command->data_dmatag, command->data_dmamap, iobuf->bio_data, iobuf->bio_bcount, ips_io_request_callback, command, 0); return 0; } void ips_start_io_request(ips_softc_t *sc) { struct bio *iobuf; ips_command_t *command; iobuf = bioq_first(&sc->queue); if(!iobuf) return; if (ips_get_free_cmd(sc, &command, 0)) return; bioq_remove(&sc->queue, iobuf); ips_send_io_request(command, iobuf); return; } /* Below are a series of functions for sending an adapter info request * to the adapter. The flow order is: get, send, callback. It uses * the generic finish callback at the top of this file. * This can be used to get configuration/status info from the card */ static void ips_adapter_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) { ips_softc_t *sc; ips_command_t *command = cmdptr; ips_adapter_info_cmd *command_struct; sc = command->sc; if(error){ ips_set_error(command, error); printf("ips: error = %d in ips_get_adapter_info\n", error); return; } command_struct = (ips_adapter_info_cmd *)command->command_buffer; command_struct->command = IPS_ADAPTER_INFO_CMD; command_struct->id = command->id; command_struct->buffaddr = segments[0].ds_addr; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_PREREAD); sc->ips_issue_cmd(command); if (sema_timedwait(&sc->cmd_sema, 30*hz) != 0) { ips_set_error(command, ETIMEDOUT); return; } bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_POSTREAD); memcpy(&(sc->adapter_info), command->data_buffer, IPS_ADAPTER_INFO_LEN); } static int ips_send_adapter_info_cmd(ips_command_t *command) { int error = 0; ips_softc_t *sc = command->sc; if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, /* alignemnt */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ IPS_ADAPTER_INFO_LEN, /* numsegs */ 1, /* maxsegsize*/ IPS_ADAPTER_INFO_LEN, /* flags */ 0, /* lockfunc */ NULL, /* lockarg */ NULL, &command->data_dmatag) != 0) { printf("ips: can't alloc dma tag for adapter status\n"); error = ENOMEM; goto exit; } if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, BUS_DMA_NOWAIT, &command->data_dmamap)){ error = ENOMEM; goto exit; } command->callback = ips_wakeup_callback; error = bus_dmamap_load(command->data_dmatag, command->data_dmamap, command->data_buffer,IPS_ADAPTER_INFO_LEN, ips_adapter_info_callback, command, BUS_DMA_NOWAIT); if (error == 0) bus_dmamap_unload(command->data_dmatag, command->data_dmamap); exit: /* I suppose I should clean up my memory allocations */ bus_dmamem_free(command->data_dmatag, command->data_buffer, command->data_dmamap); bus_dma_tag_destroy(command->data_dmatag); ips_insert_free_cmd(sc, command); return error; } int ips_get_adapter_info(ips_softc_t *sc) { ips_command_t *command; int error = 0; if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) > 0){ device_printf(sc->dev, "unable to get adapter configuration\n"); return ENXIO; } ips_send_adapter_info_cmd(command); if (COMMAND_ERROR(command)){ error = ENXIO; } return error; } /* Below are a series of functions for sending a drive info request * to the adapter. The flow order is: get, send, callback. It uses * the generic finish callback at the top of this file. * This can be used to get drive status info from the card */ static void ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) { ips_softc_t *sc; ips_command_t *command = cmdptr; ips_drive_cmd *command_struct; ips_drive_info_t *driveinfo; sc = command->sc; if(error){ ips_set_error(command, error); printf("ips: error = %d in ips_get_drive_info\n", error); return; } command_struct = (ips_drive_cmd *)command->command_buffer; command_struct->command = IPS_DRIVE_INFO_CMD; command_struct->id = command->id; command_struct->buffaddr = segments[0].ds_addr; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_PREREAD); sc->ips_issue_cmd(command); if (sema_timedwait(&sc->cmd_sema, 10*hz) != 0) { ips_set_error(command, ETIMEDOUT); return; } bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_POSTREAD); driveinfo = command->data_buffer; memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8); sc->drivecount = driveinfo->drivecount; device_printf(sc->dev, "logical drives: %d\n",sc->drivecount); } static int ips_send_drive_info_cmd(ips_command_t *command) { int error = 0; ips_softc_t *sc = command->sc; if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, /* alignemnt */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ IPS_DRIVE_INFO_LEN, /* numsegs */ 1, /* maxsegsize*/ IPS_DRIVE_INFO_LEN, /* flags */ 0, /* lockfunc */ NULL, /* lockarg */ NULL, &command->data_dmatag) != 0) { printf("ips: can't alloc dma tag for drive status\n"); error = ENOMEM; goto exit; } if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, BUS_DMA_NOWAIT, &command->data_dmamap)){ error = ENOMEM; goto exit; } command->callback = ips_wakeup_callback; error = bus_dmamap_load(command->data_dmatag, command->data_dmamap, command->data_buffer,IPS_DRIVE_INFO_LEN, ips_drive_info_callback, command, BUS_DMA_NOWAIT); if (error == 0) bus_dmamap_unload(command->data_dmatag, command->data_dmamap); exit: /* I suppose I should clean up my memory allocations */ bus_dmamem_free(command->data_dmatag, command->data_buffer, command->data_dmamap); bus_dma_tag_destroy(command->data_dmatag); ips_insert_free_cmd(sc, command); return error; } int ips_get_drive_info(ips_softc_t *sc) { int error = 0; ips_command_t *command; if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) > 0){ device_printf(sc->dev, "unable to get drive configuration\n"); return ENXIO; } ips_send_drive_info_cmd(command); if(COMMAND_ERROR(command)){ error = ENXIO; } return error; } /* Below is a pair of functions for making sure data is safely * on disk by flushing the adapter's cache. */ static int ips_send_flush_cache_cmd(ips_command_t *command) { ips_softc_t *sc = command->sc; ips_generic_cmd *command_struct; PRINTF(10,"ips test: got a command, building flush command\n"); command->callback = ips_wakeup_callback; command_struct = (ips_generic_cmd *)command->command_buffer; command_struct->command = IPS_CACHE_FLUSH_CMD; command_struct->id = command->id; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); sc->ips_issue_cmd(command); if (COMMAND_ERROR(command) == 0) sema_wait(&sc->cmd_sema); ips_insert_free_cmd(sc, command); return 0; } int ips_flush_cache(ips_softc_t *sc) { ips_command_t *command; device_printf(sc->dev, "flushing cache\n"); if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){ device_printf(sc->dev, "ERROR: unable to get a command! can't flush cache!\n"); } ips_send_flush_cache_cmd(command); if(COMMAND_ERROR(command)){ device_printf(sc->dev, "ERROR: cache flush command failed!\n"); } return 0; } /* Simplified localtime to provide timevalues for ffdc. * Taken from libc/stdtime/localtime.c */ void static ips_ffdc_settime(ips_adapter_ffdc_cmd *command, time_t sctime) { long days, rem, y; int yleap, *ip, month; int year_lengths[2] = { IPS_DAYSPERNYEAR, IPS_DAYSPERLYEAR }; int mon_lengths[2][IPS_MONSPERYEAR] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; days = sctime / IPS_SECSPERDAY; rem = sctime % IPS_SECSPERDAY; command->hour = rem / IPS_SECSPERHOUR; rem = rem % IPS_SECSPERHOUR; command->minute = rem / IPS_SECSPERMIN; command->second = rem % IPS_SECSPERMIN; y = IPS_EPOCH_YEAR; while (days < 0 || days >= (long) year_lengths[yleap = ips_isleap(y)]) { long newy; newy = y + days / IPS_DAYSPERNYEAR; if (days < 0) --newy; days -= (newy - y) * IPS_DAYSPERNYEAR + IPS_LEAPS_THRU_END_OF(newy - 1) - IPS_LEAPS_THRU_END_OF(y - 1); y = newy; } command->yearH = y / 100; command->yearL = y % 100; ip = mon_lengths[yleap]; for(month = 0; days >= (long) ip[month]; ++month) days = days - (long) ip[month]; command->month = month + 1; command->day = days + 1; } static int ips_send_ffdc_reset_cmd(ips_command_t *command) { ips_softc_t *sc = command->sc; ips_adapter_ffdc_cmd *command_struct; PRINTF(10,"ips test: got a command, building ffdc reset command\n"); command->callback = ips_wakeup_callback; command_struct = (ips_adapter_ffdc_cmd *)command->command_buffer; command_struct->command = IPS_FFDC_CMD; command_struct->id = command->id; command_struct->reset_count = sc->ffdc_resetcount; command_struct->reset_type = 0x0; ips_ffdc_settime(command_struct, sc->ffdc_resettime.tv_sec); bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); sc->ips_issue_cmd(command); if (COMMAND_ERROR(command) == 0) sema_wait(&sc->cmd_sema); ips_insert_free_cmd(sc, command); return 0; } int ips_ffdc_reset(ips_softc_t *sc) { ips_command_t *command; if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){ device_printf(sc->dev, "ERROR: unable to get a command! can't send ffdc reset!\n"); } ips_send_ffdc_reset_cmd(command); if(COMMAND_ERROR(command)){ device_printf(sc->dev, "ERROR: ffdc reset command failed!\n"); } return 0; } static void ips_write_nvram(ips_command_t *command){ ips_softc_t *sc = command->sc; ips_rw_nvram_cmd *command_struct; ips_nvram_page5 *nvram; /*FIXME check for error */ command->callback = ips_wakeup_callback; command_struct = (ips_rw_nvram_cmd *)command->command_buffer; command_struct->command = IPS_RW_NVRAM_CMD; command_struct->id = command->id; command_struct->pagenum = 5; command_struct->rw = 1; /*write*/ bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_POSTREAD); nvram = command->data_buffer; /* retrieve adapter info and save in sc */ sc->adapter_type = nvram->adapter_type; strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4); strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4); nvram->operating_system = IPS_OS_FREEBSD; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); sc->ips_issue_cmd(command); } static void ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) { ips_softc_t *sc; ips_command_t *command = cmdptr; ips_rw_nvram_cmd *command_struct; sc = command->sc; if(error){ ips_set_error(command, error); printf("ips: error = %d in ips_read_nvram_callback\n", error); return; } command_struct = (ips_rw_nvram_cmd *)command->command_buffer; command_struct->command = IPS_RW_NVRAM_CMD; command_struct->id = command->id; command_struct->pagenum = 5; command_struct->rw = 0; command_struct->buffaddr = segments[0].ds_addr; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_PREREAD); sc->ips_issue_cmd(command); if (sema_timedwait(&sc->cmd_sema, 30*hz) != 0) { ips_set_error(command, ETIMEDOUT); return; } bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_POSTWRITE); } static int ips_read_nvram(ips_command_t *command) { int error = 0; ips_softc_t *sc = command->sc; if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, /* alignemnt */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ IPS_NVRAM_PAGE_SIZE, /* numsegs */ 1, /* maxsegsize*/ IPS_NVRAM_PAGE_SIZE, /* flags */ 0, /* lockfunc */ NULL, /* lockarg */ NULL, &command->data_dmatag) != 0) { printf("ips: can't alloc dma tag for nvram\n"); error = ENOMEM; goto exit; } if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, BUS_DMA_NOWAIT, &command->data_dmamap)){ error = ENOMEM; goto exit; } command->callback = ips_write_nvram; error = bus_dmamap_load(command->data_dmatag, command->data_dmamap, command->data_buffer,IPS_NVRAM_PAGE_SIZE, ips_read_nvram_callback, command, BUS_DMA_NOWAIT); if (error == 0) bus_dmamap_unload(command->data_dmatag, command->data_dmamap); exit: bus_dmamem_free(command->data_dmatag, command->data_buffer, command->data_dmamap); bus_dma_tag_destroy(command->data_dmatag); ips_insert_free_cmd(sc, command); return error; } int ips_update_nvram(ips_softc_t *sc) { ips_command_t *command; if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){ device_printf(sc->dev, "ERROR: unable to get a command! can't update nvram\n"); return 1; } ips_read_nvram(command); if(COMMAND_ERROR(command)){ device_printf(sc->dev, "ERROR: nvram update command failed!\n"); } return 0; } static int ips_send_config_sync_cmd(ips_command_t *command) { ips_softc_t *sc = command->sc; ips_generic_cmd *command_struct; PRINTF(10,"ips test: got a command, building flush command\n"); command->callback = ips_wakeup_callback; command_struct = (ips_generic_cmd *)command->command_buffer; command_struct->command = IPS_CONFIG_SYNC_CMD; command_struct->id = command->id; command_struct->reserve2 = IPS_POCL; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); sc->ips_issue_cmd(command); if (COMMAND_ERROR(command) == 0) sema_wait(&sc->cmd_sema); ips_insert_free_cmd(sc, command); return 0; } static int ips_send_error_table_cmd(ips_command_t *command) { ips_softc_t *sc = command->sc; ips_generic_cmd *command_struct; PRINTF(10,"ips test: got a command, building errortable command\n"); command->callback = ips_wakeup_callback; command_struct = (ips_generic_cmd *)command->command_buffer; command_struct->command = IPS_ERROR_TABLE_CMD; command_struct->id = command->id; command_struct->reserve2 = IPS_CSL; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); sc->ips_issue_cmd(command); if (COMMAND_ERROR(command) == 0) sema_wait(&sc->cmd_sema); ips_insert_free_cmd(sc, command); return 0; } int ips_clear_adapter(ips_softc_t *sc) { ips_command_t *command; device_printf(sc->dev, "syncing config\n"); if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){ device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n"); return 1; } ips_send_config_sync_cmd(command); if(COMMAND_ERROR(command)){ device_printf(sc->dev, "ERROR: cache sync command failed!\n"); return 1; } device_printf(sc->dev, "clearing error table\n"); if(ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){ device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n"); return 1; } ips_send_error_table_cmd(command); if(COMMAND_ERROR(command)){ device_printf(sc->dev, "ERROR: etable command failed!\n"); return 1; } return 0; } Index: head/sys/dev/ips/ips_disk.c =================================================================== --- head/sys/dev/ips/ips_disk.c (revision 152918) +++ head/sys/dev/ips/ips_disk.c (revision 152919) @@ -1,302 +1,303 @@ /*- * Written by: David Jeffery * Copyright (c) 2002 Adaptec Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); +#include #include #include #include static int ipsd_probe(device_t dev); static int ipsd_attach(device_t dev); static int ipsd_detach(device_t dev); static int ipsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length); static void ipsd_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error); static void ipsd_dump_block_complete(ips_command_t *command); static disk_open_t ipsd_open; static disk_close_t ipsd_close; static disk_strategy_t ipsd_strategy; static device_method_t ipsd_methods[] = { DEVMETHOD(device_probe, ipsd_probe), DEVMETHOD(device_attach, ipsd_attach), DEVMETHOD(device_detach, ipsd_detach), { 0, 0 } }; static driver_t ipsd_driver = { "ipsd", ipsd_methods, sizeof(ipsdisk_softc_t) }; static devclass_t ipsd_devclass; DRIVER_MODULE(ipsd, ips, ipsd_driver, ipsd_devclass, 0, 0); /* handle opening of disk device. It must set up all information about the geometry and size of the disk */ static int ipsd_open(struct disk *dp) { ipsdisk_softc_t *dsc = dp->d_drv1; dsc->state |= IPS_DEV_OPEN; DEVICE_PRINTF(2, dsc->dev, "I'm open\n"); return 0; } static int ipsd_close(struct disk *dp) { ipsdisk_softc_t *dsc = dp->d_drv1; dsc->state &= ~IPS_DEV_OPEN; DEVICE_PRINTF(2, dsc->dev, "I'm closed for the day\n"); return 0; } /* ipsd_finish is called to clean up and return a completed IO request */ void ipsd_finish(struct bio *iobuf) { ipsdisk_softc_t *dsc; dsc = iobuf->bio_disk->d_drv1; if (iobuf->bio_flags & BIO_ERROR) { ipsdisk_softc_t *dsc; dsc = iobuf->bio_disk->d_drv1; device_printf(dsc->dev, "iobuf error %d\n", iobuf->bio_error); } else iobuf->bio_resid = 0; biodone(iobuf); ips_start_io_request(dsc->sc); } static void ipsd_strategy(struct bio *iobuf) { ipsdisk_softc_t *dsc; dsc = iobuf->bio_disk->d_drv1; DEVICE_PRINTF(8,dsc->dev,"in strategy\n"); iobuf->bio_driver1 = (void *)(uintptr_t)dsc->sc->drives[dsc->disk_number].drivenum; mtx_lock(&dsc->sc->queue_mtx); bioq_insert_tail(&dsc->sc->queue, iobuf); ips_start_io_request(dsc->sc); mtx_unlock(&dsc->sc->queue_mtx); } static int ipsd_probe(device_t dev) { DEVICE_PRINTF(2,dev, "in probe\n"); device_set_desc(dev, "Logical Drive"); return 0; } static int ipsd_attach(device_t dev) { device_t adapter; ipsdisk_softc_t *dsc; u_int totalsectors; DEVICE_PRINTF(2,dev, "in attach\n"); dsc = (ipsdisk_softc_t *)device_get_softc(dev); bzero(dsc, sizeof(ipsdisk_softc_t)); adapter = device_get_parent(dev); dsc->dev = dev; dsc->sc = device_get_softc(adapter); dsc->unit = device_get_unit(dev); dsc->disk_number = (uintptr_t) device_get_ivars(dev); dsc->ipsd_disk = disk_alloc(); dsc->ipsd_disk->d_drv1 = dsc; dsc->ipsd_disk->d_name = "ipsd"; dsc->ipsd_disk->d_maxsize = IPS_MAX_IO_SIZE; dsc->ipsd_disk->d_open = ipsd_open; dsc->ipsd_disk->d_close = ipsd_close; dsc->ipsd_disk->d_strategy = ipsd_strategy; dsc->ipsd_disk->d_dump = ipsd_dump; totalsectors = dsc->sc->drives[dsc->disk_number].sector_count; if ((totalsectors > 0x400000) && ((dsc->sc->adapter_info.miscflags & 0x8) == 0)) { dsc->ipsd_disk->d_fwheads = IPS_NORM_HEADS; dsc->ipsd_disk->d_fwsectors = IPS_NORM_SECTORS; } else { dsc->ipsd_disk->d_fwheads = IPS_COMP_HEADS; dsc->ipsd_disk->d_fwsectors = IPS_COMP_SECTORS; } dsc->ipsd_disk->d_sectorsize = IPS_BLKSIZE; dsc->ipsd_disk->d_mediasize = (off_t)totalsectors * IPS_BLKSIZE; dsc->ipsd_disk->d_unit = dsc->unit; dsc->ipsd_disk->d_flags = 0; disk_create(dsc->ipsd_disk, DISK_VERSION); device_printf(dev, "Logical Drive (%dMB)\n", dsc->sc->drives[dsc->disk_number].sector_count >> 11); return 0; } static int ipsd_detach(device_t dev) { ipsdisk_softc_t *dsc; DEVICE_PRINTF(2, dev,"in detach\n"); dsc = (ipsdisk_softc_t *)device_get_softc(dev); if(dsc->state & IPS_DEV_OPEN) return (EBUSY); disk_destroy(dsc->ipsd_disk); return 0; } static int ipsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) { ipsdisk_softc_t *dsc; ips_softc_t *sc; ips_command_t *command; ips_io_cmd *command_struct; struct disk *dp; void *va; off_t off; size_t len; int error = 0; dp = arg; dsc = dp->d_drv1; sc = dsc->sc; if (dsc == NULL) return (EINVAL); if (ips_get_free_cmd(sc, &command, 0) != 0) { printf("ipsd: failed to get cmd for dump\n"); return (ENOMEM); } command->data_dmatag = sc->sg_dmatag; command->callback = ipsd_dump_block_complete; command_struct = (ips_io_cmd *)command->command_buffer; command_struct->id = command->id; command_struct->drivenum= sc->drives[dsc->disk_number].drivenum; off = offset; va = virtual; while (length > 0) { len = (length > IPS_MAX_IO_SIZE) ? IPS_MAX_IO_SIZE : length; command_struct->lba = off / IPS_BLKSIZE; if (bus_dmamap_load(command->data_dmatag, command->data_dmamap, va, len, ipsd_dump_map_sg, command, BUS_DMA_NOWAIT) != 0) { error = EIO; break; } if (COMMAND_ERROR(command)) { error = EIO; break; } length -= len; off += len; va = (uint8_t *)va + len; } ips_insert_free_cmd(command->sc, command); return (error); } static void ipsd_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { ips_softc_t *sc; ips_command_t *command; ips_sg_element_t *sg_list; ips_io_cmd *command_struct; int i, length; command = (ips_command_t *)arg; sc = command->sc; length = 0; if (error) { printf("ipsd_dump_map_sg: error %d\n", error); ips_set_error(command, error); return; } command_struct = (ips_io_cmd *)command->command_buffer; if (nsegs != 1) { command_struct->segnum = nsegs; sg_list = (ips_sg_element_t *)((uint8_t *) command->command_buffer + IPS_COMMAND_LEN); for (i = 0; i < nsegs; i++) { sg_list[i].addr = segs[i].ds_addr; sg_list[i].len = segs[i].ds_len; length += segs[i].ds_len; } command_struct->buffaddr = (uint32_t)command->command_phys_addr + IPS_COMMAND_LEN; command_struct->command = IPS_SG_WRITE_CMD; } else { command_struct->buffaddr = segs[0].ds_addr; length = segs[0].ds_len; command_struct->segnum = 0; command_struct->command = IPS_WRITE_CMD; } length = (length + IPS_BLKSIZE - 1) / IPS_BLKSIZE; command_struct->length = length; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_PREWRITE); sc->ips_issue_cmd(command); sc->ips_poll_cmd(command); return; } static void ipsd_dump_block_complete(ips_command_t *command) { if (COMMAND_ERROR(command)) printf("ipsd_dump completion error= 0x%x\n", command->status.value); bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(command->data_dmatag, command->data_dmamap); } Index: head/sys/dev/ips/ips_ioctl.c =================================================================== --- head/sys/dev/ips/ips_ioctl.c (revision 152918) +++ head/sys/dev/ips/ips_ioctl.c (revision 152919) @@ -1,169 +1,170 @@ /*- * Written by: David Jeffery * Copyright (c) 2002 Adaptec Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); +#include #include #include static void ips_ioctl_finish(ips_command_t *command) { ips_ioctl_t *ioctl_cmd = command->arg; if(ioctl_cmd->readwrite & IPS_IOCTL_READ){ bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap, BUS_DMASYNC_POSTREAD); } else if(ioctl_cmd->readwrite & IPS_IOCTL_WRITE){ bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap, BUS_DMASYNC_POSTWRITE); } bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ioctl_cmd->dmatag, ioctl_cmd->dmamap); ioctl_cmd->status.value = command->status.value; ips_insert_free_cmd(command->sc, command); } static void ips_ioctl_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) { ips_command_t *command = cmdptr; ips_ioctl_t *ioctl_cmd = command->arg; ips_generic_cmd *command_buffer = command->command_buffer; if(error){ ips_set_error(command, error); return; } command_buffer->id = command->id; command_buffer->buffaddr = segments[0].ds_addr; if(ioctl_cmd->readwrite & IPS_IOCTL_WRITE){ bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap, BUS_DMASYNC_PREWRITE); } else if(ioctl_cmd->readwrite & IPS_IOCTL_READ){ bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap, BUS_DMASYNC_PREREAD); } bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); command->sc->ips_issue_cmd(command); } static int ips_ioctl_start(ips_command_t *command) { ips_ioctl_t *ioctl_cmd = command->arg; memcpy(command->command_buffer, ioctl_cmd->command_buffer, sizeof(ips_generic_cmd)); command->callback = ips_ioctl_finish; bus_dmamap_load(ioctl_cmd->dmatag, ioctl_cmd->dmamap, ioctl_cmd->data_buffer,ioctl_cmd->datasize, ips_ioctl_callback, command, 0); return 0; } static int ips_ioctl_cmd(ips_softc_t *sc, ips_ioctl_t *ioctl_cmd, ips_user_request *user_request) { ips_command_t *command; int error = EINVAL; if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, /* alignment */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ ioctl_cmd->datasize, /* numsegs */ 1, /* maxsegsize*/ ioctl_cmd->datasize, /* flags */ 0, /* lockfunc */ NULL, /* lockarg */ NULL, &ioctl_cmd->dmatag) != 0) { return ENOMEM; } if(bus_dmamem_alloc(ioctl_cmd->dmatag, &ioctl_cmd->data_buffer, 0, &ioctl_cmd->dmamap)){ error = ENOMEM; goto exit; } if(copyin(user_request->data_buffer,ioctl_cmd->data_buffer, ioctl_cmd->datasize)) goto exit; ioctl_cmd->status.value = 0xffffffff; mtx_lock(&sc->queue_mtx); if((error = ips_get_free_cmd(sc, &command, 0)) > 0){ error = ENOMEM; mtx_unlock(&sc->queue_mtx); goto exit; } command->arg = ioctl_cmd; ips_ioctl_start(command); while( ioctl_cmd->status.value == 0xffffffff) msleep(ioctl_cmd, &sc->queue_mtx, 0, "ips", hz/10); if(COMMAND_ERROR(ioctl_cmd)) error = EIO; else error = 0; mtx_unlock(&sc->queue_mtx); if(copyout(ioctl_cmd->data_buffer, user_request->data_buffer, ioctl_cmd->datasize)) error = EINVAL; mtx_lock(&sc->queue_mtx); ips_insert_free_cmd(sc, command); mtx_unlock(&sc->queue_mtx); exit: bus_dmamem_free(ioctl_cmd->dmatag, ioctl_cmd->data_buffer, ioctl_cmd->dmamap); bus_dma_tag_destroy(ioctl_cmd->dmatag); return error; } int ips_ioctl_request(ips_softc_t *sc, u_long ioctl_request, caddr_t addr, int32_t flags){ int error = EINVAL; ips_ioctl_t *ioctl_cmd; ips_user_request *user_request; switch(ioctl_request){ case IPS_USER_CMD: user_request = (ips_user_request *)addr; ioctl_cmd = malloc(sizeof(ips_ioctl_t), M_IPSBUF, M_WAITOK); ioctl_cmd->command_buffer = malloc(sizeof(ips_generic_cmd), M_IPSBUF, M_WAITOK); if(copyin(user_request->command_buffer, ioctl_cmd->command_buffer, sizeof(ips_generic_cmd))){ free(ioctl_cmd->command_buffer, M_IPSBUF); free(ioctl_cmd, M_IPSBUF); break; } ioctl_cmd->readwrite = IPS_IOCTL_READ | IPS_IOCTL_WRITE; ioctl_cmd->datasize = IPS_IOCTL_BUFFER_SIZE; error = ips_ioctl_cmd(sc, ioctl_cmd, user_request); free(ioctl_cmd->command_buffer, M_IPSBUF); free(ioctl_cmd, M_IPSBUF); break; } return error; } Index: head/sys/dev/ips/ips_pci.c =================================================================== --- head/sys/dev/ips/ips_pci.c (revision 152918) +++ head/sys/dev/ips/ips_pci.c (revision 152919) @@ -1,233 +1,237 @@ /*- * Copyright (c) 2002 Adaptec Inc. * All rights reserved. * * Written by: David Jeffery * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); +#include #include + +#include +#include static int ips_pci_free(ips_softc_t *sc); static void ips_intrhook(void *arg); static int ips_pci_probe(device_t dev) { if ((pci_get_vendor(dev) == IPS_VENDOR_ID) && (pci_get_device(dev) == IPS_MORPHEUS_DEVICE_ID)) { device_set_desc(dev, "IBM ServeRAID Adapter"); return (BUS_PROBE_DEFAULT); } else if ((pci_get_vendor(dev) == IPS_VENDOR_ID) && (pci_get_device(dev) == IPS_COPPERHEAD_DEVICE_ID)) { device_set_desc(dev, "IBM ServeRAID Adapter"); return (BUS_PROBE_DEFAULT); } else if ((pci_get_vendor(dev) == IPS_VENDOR_ID_ADAPTEC) && (pci_get_device(dev) == IPS_MARCO_DEVICE_ID)) { device_set_desc(dev, "Adaptec ServeRAID Adapter"); return (BUS_PROBE_DEFAULT); } return(ENXIO); } static int ips_pci_attach(device_t dev) { u_int32_t command; ips_softc_t *sc; if (resource_disabled(device_get_name(dev), device_get_unit(dev))) { device_printf(dev, "device is disabled\n"); /* but return 0 so the !$)$)*!$*) unit isn't reused */ return (0); } DEVICE_PRINTF(1, dev, "in attach.\n"); sc = (ips_softc_t *)device_get_softc(dev); if(!sc){ printf("how is sc NULL?!\n"); return (ENXIO); } bzero(sc, sizeof(ips_softc_t)); sc->dev = dev; if(pci_get_device(dev) == IPS_MORPHEUS_DEVICE_ID){ sc->ips_adapter_reinit = ips_morpheus_reinit; sc->ips_adapter_intr = ips_morpheus_intr; sc->ips_issue_cmd = ips_issue_morpheus_cmd; sc->ips_poll_cmd = ips_morpheus_poll; } else if(pci_get_device(dev) == IPS_COPPERHEAD_DEVICE_ID){ sc->ips_adapter_reinit = ips_copperhead_reinit; sc->ips_adapter_intr = ips_copperhead_intr; sc->ips_issue_cmd = ips_issue_copperhead_cmd; sc->ips_poll_cmd = ips_copperhead_poll; } else if (pci_get_device(dev) == IPS_MARCO_DEVICE_ID){ sc->ips_adapter_reinit = ips_morpheus_reinit; sc->ips_adapter_intr = ips_morpheus_intr; sc->ips_issue_cmd = ips_issue_morpheus_cmd; sc->ips_poll_cmd = ips_morpheus_poll; } else goto error; /* make sure busmastering is on */ command = pci_read_config(dev, PCIR_COMMAND, 1); command |= PCIM_CMD_BUSMASTEREN; pci_write_config(dev, PCIR_COMMAND, command, 1); /* seting up io space */ sc->iores = NULL; if(command & PCIM_CMD_MEMEN){ PRINTF(10, "trying MEMIO\n"); if(pci_get_device(dev) == IPS_COPPERHEAD_DEVICE_ID) sc->rid = PCIR_BAR(1); else sc->rid = PCIR_BAR(0); sc->iotype = SYS_RES_MEMORY; sc->iores = bus_alloc_resource_any(dev, sc->iotype, &sc->rid, RF_ACTIVE); } if(!sc->iores && command & PCIM_CMD_PORTEN){ PRINTF(10, "trying PORTIO\n"); sc->rid = PCIR_BAR(0); sc->iotype = SYS_RES_IOPORT; sc->iores = bus_alloc_resource_any(dev, sc->iotype, &sc->rid, RF_ACTIVE); } if(sc->iores == NULL){ device_printf(dev, "resource allocation failed\n"); return (ENXIO); } sc->bustag = rman_get_bustag(sc->iores); sc->bushandle = rman_get_bushandle(sc->iores); /*allocate an interrupt. when does the irq become active? after leaving attach? */ sc->irqrid = 0; if(!(sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqrid, RF_SHAREABLE | RF_ACTIVE))){ device_printf(dev, "irq allocation failed\n"); goto error; } if(bus_setup_intr(dev, sc->irqres, INTR_TYPE_BIO|INTR_MPSAFE, sc->ips_adapter_intr, sc, &sc->irqcookie)){ device_printf(dev, "irq setup failed\n"); goto error; } if (bus_dma_tag_create( /* parent */ NULL, /* alignemnt */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, /* numsegs */ IPS_MAX_SG_ELEMENTS, /* maxsegsize*/ BUS_SPACE_MAXSIZE_32BIT, /* flags */ 0, /* lockfunc */ NULL, /* lockarg */ NULL, &sc->adapter_dmatag) != 0) { printf("IPS can't alloc dma tag\n"); goto error; } sc->ips_ich.ich_func = ips_intrhook; sc->ips_ich.ich_arg = sc; mtx_init(&sc->queue_mtx, "IPS bioqueue lock", MTX_DEF, 0); sema_init(&sc->cmd_sema, 0, "IPS Command Semaphore"); bioq_init(&sc->queue); if (config_intrhook_establish(&sc->ips_ich) != 0) { printf("IPS can't establish configuration hook\n"); goto error; } return 0; error: ips_pci_free(sc); return (ENXIO); } static void ips_intrhook(void *arg) { struct ips_softc *sc = (struct ips_softc *)arg; config_intrhook_disestablish(&sc->ips_ich); if (ips_adapter_init(sc)) ips_pci_free(sc); else sc->configured = 1; } static int ips_pci_free(ips_softc_t *sc) { if(sc->adapter_dmatag) bus_dma_tag_destroy(sc->adapter_dmatag); if(sc->irqcookie) bus_teardown_intr(sc->dev, sc->irqres, sc->irqcookie); if(sc->irqres) bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irqrid, sc->irqres); if(sc->iores) bus_release_resource(sc->dev, sc->iotype, sc->rid, sc->iores); sc->configured = 0; mtx_destroy(&sc->queue_mtx); sema_destroy(&sc->cmd_sema); return 0; } static int ips_pci_detach(device_t dev) { ips_softc_t *sc; DEVICE_PRINTF(1, dev, "detaching ServeRaid\n"); sc = (ips_softc_t *) device_get_softc(dev); if (sc->configured) { sc->configured = 0; ips_flush_cache(sc); if(ips_adapter_free(sc)) return EBUSY; ips_pci_free(sc); bioq_flush(&sc->queue, NULL, ENXIO); } return 0; } static int ips_pci_shutdown(device_t dev) { ips_softc_t *sc = (ips_softc_t *) device_get_softc(dev); if (sc->configured) { ips_flush_cache(sc); } return 0; } static device_method_t ips_driver_methods[] = { DEVMETHOD(device_probe, ips_pci_probe), DEVMETHOD(device_attach, ips_pci_attach), DEVMETHOD(device_detach, ips_pci_detach), DEVMETHOD(device_shutdown, ips_pci_shutdown), {0,0} }; static driver_t ips_pci_driver = { "ips", ips_driver_methods, sizeof(ips_softc_t), }; static devclass_t ips_devclass; DRIVER_MODULE(ips, pci, ips_pci_driver, ips_devclass, 0, 0); Index: head/sys/dev/ips/ipsreg.h =================================================================== --- head/sys/dev/ips/ipsreg.h (nonexistent) +++ head/sys/dev/ips/ipsreg.h (revision 152919) @@ -0,0 +1,337 @@ +/*- + * Copyright (c) 2002 Adaptec Inc. + * All rights reserved. + * + * Written by: David Jeffery + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + +/* + * IPS CONSTANTS + */ +#define IPS_VENDOR_ID 0x1014 +#define IPS_VENDOR_ID_ADAPTEC 0x9005 +#define IPS_MORPHEUS_DEVICE_ID 0x01BD +#define IPS_COPPERHEAD_DEVICE_ID 0x002E +#define IPS_MARCO_DEVICE_ID 0x0250 +#define IPS_CSL 0xff +#define IPS_POCL 0x30 + +/* amounts of memory to allocate for certain commands */ +#define IPS_ADAPTER_INFO_LEN (sizeof(ips_adapter_info_t)) +#define IPS_DRIVE_INFO_LEN (sizeof(ips_drive_info_t)) +#define IPS_COMMAND_LEN 24 +#define IPS_MAX_SG_LEN (sizeof(ips_sg_element_t) * IPS_MAX_SG_ELEMENTS) +#define IPS_NVRAM_PAGE_SIZE 128 +/* various flags */ +#define IPS_STATIC_FLAG 0x01 + +/* states for the card to be in */ +#define IPS_DEV_OPEN 0x01 +#define IPS_TIMEOUT 0x02 /* command time out, need reset */ +#define IPS_OFFLINE 0x04 /* can't reset card/card failure */ +#define IPS_STATIC_BUSY 0x08 + +/* max number of commands set to something low for now */ +#define IPS_MAX_CMD_NUM 128 +#define IPS_MAX_NUM_DRIVES 8 +#define IPS_MAX_SG_ELEMENTS 32 +#define IPS_MAX_IOBUF_SIZE (64 * 1024) +#define IPS_BLKSIZE 512 + +/* logical drive states */ + +#define IPS_LD_OFFLINE 0x02 +#define IPS_LD_OKAY 0x03 +#define IPS_LD_DEGRADED 0x04 +#define IPS_LD_FREE 0x00 +#define IPS_LD_SYS 0x06 +#define IPS_LD_CRS 0x24 + +/* register offsets */ +#define MORPHEUS_REG_OMR0 0x0018 /* Outbound Msg. Reg. 0 */ +#define MORPHEUS_REG_OMR1 0x001C /* Outbound Msg. Reg. 1 */ +#define MORPHEUS_REG_IDR 0x0020 /* Inbound Doorbell Reg. */ +#define MORPHEUS_REG_IISR 0x0024 /* Inbound IRQ Status Reg. */ +#define MORPHEUS_REG_IIMR 0x0028 /* Inbound IRQ Mask Reg. */ +#define MORPHEUS_REG_OISR 0x0030 /* Outbound IRQ Status Reg. */ +#define MORPHEUS_REG_OIMR 0x0034 /* Outbound IRQ Mask Reg. */ +#define MORPHEUS_REG_IQPR 0x0040 /* Inbound Queue Port Reg. */ +#define MORPHEUS_REG_OQPR 0x0044 /* Outbound Queue Port Reg. */ + +#define COPPER_REG_SCPR 0x05 /* Subsystem Ctrl. Port Reg. */ +#define COPPER_REG_ISPR 0x06 /* IRQ Status Port Reg. */ +#define COPPER_REG_CBSP 0x07 /* ? Reg. */ +#define COPPER_REG_HISR 0x08 /* Host IRQ Status Reg. */ +#define COPPER_REG_CCSAR 0x10 /* Cmd. Channel Sys Addr Reg.*/ +#define COPPER_REG_CCCR 0x14 /* Cmd. Channel Ctrl. Reg. */ +#define COPPER_REG_SQHR 0x20 /* Status Queue Head Reg. */ +#define COPPER_REG_SQTR 0x24 /* Status Queue Tail Reg. */ +#define COPPER_REG_SQER 0x28 /* Status Queue End Reg. */ +#define COPPER_REG_SQSR 0x2C /* Status Queue Start Reg. */ + +/* bit definitions */ +#define MORPHEUS_BIT_POST1 0x01 +#define MORPHEUS_BIT_POST2 0x02 +#define MORPHEUS_BIT_CMD_IRQ 0x08 + +#define COPPER_CMD_START 0x101A +#define COPPER_SEM_BIT 0x08 +#define COPPER_EI_BIT 0x80 +#define COPPER_EBM_BIT 0x02 +#define COPPER_RESET_BIT 0x80 +#define COPPER_GHI_BIT 0x04 +#define COPPER_SCE_BIT 0x01 +#define COPPER_OP_BIT 0x01 +#define COPPER_ILE_BIT 0x10 + +/* status defines */ +#define IPS_POST1_OK 0x8000 +#define IPS_POST2_OK 0x000f + +/* command op codes */ +#define IPS_READ_CMD 0x02 +#define IPS_WRITE_CMD 0x03 +#define IPS_ADAPTER_INFO_CMD 0x05 +#define IPS_CACHE_FLUSH_CMD 0x0A +#define IPS_REBUILD_STATUS_CMD 0x0C +#define IPS_ERROR_TABLE_CMD 0x17 +#define IPS_DRIVE_INFO_CMD 0x19 +#define IPS_SUBSYS_PARAM_CMD 0x40 +#define IPS_CONFIG_SYNC_CMD 0x58 +#define IPS_SG_READ_CMD 0x82 +#define IPS_SG_WRITE_CMD 0x83 +#define IPS_RW_NVRAM_CMD 0xBC +#define IPS_FFDC_CMD 0xD7 + +/* basic_status information returned by the adapter */ +#define IPS_MIN_ERROR 0x02 +#define IPS_BASIC_STATUS_MASK 0xFF +#define IPS_GSC_STATUS_MASK 0x0F +#define IPS_CMD_SUCCESS 0x00 +#define IPS_CMD_RECOVERED_ERROR 0x01 +#define IPS_DRV_ERROR 0x02 /* Driver supplied error */ +#define IPS_INVAL_OPCO 0x03 +#define IPS_INVAL_CMD_BLK 0x04 +#define IPS_INVAL_PARM_BLK 0x05 +#define IPS_BUSY 0x08 +#define IPS_CMD_CMPLT_WERROR 0x0C +#define IPS_LD_ERROR 0x0D +#define IPS_CMD_TIMEOUT 0x0E +#define IPS_PHYS_DRV_ERROR 0x0F + +/* extended_status information returned by the adapter */ +#define IPS_ERR_SEL_TO 0xF0 +#define IPS_ERR_OU_RUN 0xF2 +#define IPS_ERR_HOST_RESET 0xF7 +#define IPS_ERR_DEV_RESET 0xF8 +#define IPS_ERR_RECOVERY 0xFC +#define IPS_ERR_CKCOND 0xFF + +#define IPS_OS_FREEBSD 8 +#define IPS_VERSION_MAJOR "0.90" +#define IPS_VERSION_MINOR ".10" + +/* Adapter Types */ +#define IPS_ADAPTER_COPPERHEAD 0x01 +#define IPS_ADAPTER_COPPERHEAD2 0x02 +#define IPS_ADAPTER_COPPERHEADOB1 0x03 +#define IPS_ADAPTER_COPPERHEADOB2 0x04 +#define IPS_ADAPTER_CLARINET 0x05 +#define IPS_ADAPTER_CLARINETLITE 0x06 +#define IPS_ADAPTER_TROMBONE 0x07 +#define IPS_ADAPTER_MORPHEUS 0x08 +#define IPS_ADAPTER_MORPHEUSLITE 0x09 +#define IPS_ADAPTER_NEO 0x0A +#define IPS_ADAPTER_NEOLITE 0x0B +#define IPS_ADAPTER_SARASOTA2 0x0C +#define IPS_ADAPTER_SARASOTA1 0x0D +#define IPS_ADAPTER_MARCO 0x0E +#define IPS_ADAPTER_SEBRING 0x0F +#define IPS_ADAPTER_MAX_T IPS_ADAPTER_SEBRING + +/* values for ffdc_settime (from gmtime) */ +#define IPS_SECSPERMIN 60 +#define IPS_MINSPERHOUR 60 +#define IPS_HOURSPERDAY 24 +#define IPS_DAYSPERWEEK 7 +#define IPS_DAYSPERNYEAR 365 +#define IPS_DAYSPERLYEAR 366 +#define IPS_SECSPERHOUR (IPS_SECSPERMIN * IPS_MINSPERHOUR) +#define IPS_SECSPERDAY ((long) IPS_SECSPERHOUR * IPS_HOURSPERDAY) +#define IPS_MONSPERYEAR 12 +#define IPS_EPOCH_YEAR 1970 +#define IPS_LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) +#define ips_isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + +/* + * IPS STRUCTS + */ + +typedef struct{ + u_int8_t command; + u_int8_t id; + u_int8_t drivenum; + u_int8_t reserve2; + u_int32_t lba; + u_int32_t buffaddr; + u_int32_t reserve3; +} __attribute__ ((packed)) ips_generic_cmd; + +typedef struct{ + u_int8_t command; + u_int8_t id; + u_int8_t drivenum; + u_int8_t segnum; + u_int32_t lba; + u_int32_t buffaddr; + u_int16_t length; + u_int16_t reserve1; +} __attribute__ ((packed)) ips_io_cmd; + +typedef struct{ + u_int8_t command; + u_int8_t id; + u_int8_t pagenum; + u_int8_t rw; + u_int32_t reserve1; + u_int32_t buffaddr; + u_int32_t reserve3; +} __attribute__ ((packed)) ips_rw_nvram_cmd; + +typedef struct{ + u_int8_t command; + u_int8_t id; + u_int8_t drivenum; + u_int8_t reserve1; + u_int32_t reserve2; + u_int32_t buffaddr; + u_int32_t reserve3; +} __attribute__ ((packed)) ips_drive_cmd; + +typedef struct{ + u_int8_t command; + u_int8_t id; + u_int8_t reserve1; + u_int8_t commandtype; + u_int32_t reserve2; + u_int32_t buffaddr; + u_int32_t reserve3; +} __attribute__((packed)) ips_adapter_info_cmd; + +typedef struct{ + u_int8_t command; + u_int8_t id; + u_int8_t reset_count; + u_int8_t reset_type; + u_int8_t second; + u_int8_t minute; + u_int8_t hour; + u_int8_t day; + u_int8_t reserve1[4]; + u_int8_t month; + u_int8_t yearH; + u_int8_t yearL; + u_int8_t reserve2; +} __attribute__((packed)) ips_adapter_ffdc_cmd; + +typedef union{ + ips_generic_cmd generic_cmd; + ips_drive_cmd drive_cmd; + ips_adapter_info_cmd adapter_info_cmd; +} ips_cmd_buff_t; + +typedef struct { + u_int32_t signature; + u_int8_t reserved; + u_int8_t adapter_slot; + u_int16_t adapter_type; + u_int8_t bios_high[4]; + u_int8_t bios_low[4]; + u_int16_t reserve2; + u_int8_t reserve3; + u_int8_t operating_system; + u_int8_t driver_high[4]; + u_int8_t driver_low[4]; + u_int8_t reserve4[100]; +}__attribute__((packed)) ips_nvram_page5; + +typedef struct{ + u_int32_t addr; + u_int32_t len; +} ips_sg_element_t; + +typedef struct{ + u_int8_t drivenum; + u_int8_t merge_id; + u_int8_t raid_lvl; + u_int8_t state; + u_int32_t sector_count; +} __attribute__((packed)) ips_drive_t; + +typedef struct{ + u_int8_t drivecount; + u_int8_t reserve1; + u_int16_t reserve2; + ips_drive_t drives[IPS_MAX_NUM_DRIVES]; +}__attribute__((packed)) ips_drive_info_t; + +typedef struct{ + u_int8_t drivecount; + u_int8_t miscflags; + u_int8_t SLTflags; + u_int8_t BSTflags; + u_int8_t pwr_chg_count; + u_int8_t wrong_addr_count; + u_int8_t unident_count; + u_int8_t nvram_dev_chg_count; + u_int8_t codeblock_version[8]; + u_int8_t bootblock_version[8]; + u_int32_t drive_sector_count[IPS_MAX_NUM_DRIVES]; + u_int8_t max_concurrent_cmds; + u_int8_t max_phys_devices; + u_int16_t flash_prog_count; + u_int8_t defunct_disks; + u_int8_t rebuildflags; + u_int8_t offline_drivecount; + u_int8_t critical_drivecount; + u_int16_t config_update_count; + u_int8_t blockedflags; + u_int8_t psdn_error; + u_int16_t addr_dead_disk[4*16];/* ugly, max # channels * max # scsi devices per channel */ +}__attribute__((packed)) ips_adapter_info_t; + +typedef union { + struct { + u_int8_t reserved; + u_int8_t command_id; + u_int8_t basic_status; + u_int8_t extended_status; + } fields; + volatile u_int32_t value; +} ips_cmd_status_t; + Property changes on: head/sys/dev/ips/ipsreg.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property