ata_pmp.c revision 200218
1198389Smav/*- 2198389Smav * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 3198389Smav * All rights reserved. 4198389Smav * 5198389Smav * Redistribution and use in source and binary forms, with or without 6198389Smav * modification, are permitted provided that the following conditions 7198389Smav * are met: 8198389Smav * 1. Redistributions of source code must retain the above copyright 9198389Smav * notice, this list of conditions and the following disclaimer, 10198389Smav * without modification, immediately at the beginning of the file. 11198389Smav * 2. Redistributions in binary form must reproduce the above copyright 12198389Smav * notice, this list of conditions and the following disclaimer in the 13198389Smav * documentation and/or other materials provided with the distribution. 14198389Smav * 15198389Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16198389Smav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17198389Smav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18198389Smav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19198389Smav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20198389Smav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21198389Smav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22198389Smav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23198389Smav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24198389Smav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25198389Smav */ 26198389Smav 27198389Smav#include <sys/cdefs.h> 28198389Smav__FBSDID("$FreeBSD: head/sys/cam/ata/ata_pmp.c 200218 2009-12-07 16:23:25Z mav $"); 29198389Smav 30198389Smav#include <sys/param.h> 31198389Smav 32198389Smav#ifdef _KERNEL 33198389Smav#include <sys/systm.h> 34198389Smav#include <sys/kernel.h> 35198389Smav#include <sys/bio.h> 36198389Smav#include <sys/sysctl.h> 37198389Smav#include <sys/taskqueue.h> 38198389Smav#include <sys/lock.h> 39198389Smav#include <sys/mutex.h> 40198389Smav#include <sys/conf.h> 41198389Smav#include <sys/devicestat.h> 42198389Smav#include <sys/eventhandler.h> 43198389Smav#include <sys/malloc.h> 44198389Smav#include <sys/cons.h> 45198389Smav#include <geom/geom_disk.h> 46198389Smav#endif /* _KERNEL */ 47198389Smav 48198389Smav#ifndef _KERNEL 49198389Smav#include <stdio.h> 50198389Smav#include <string.h> 51198389Smav#endif /* _KERNEL */ 52198389Smav 53198389Smav#include <cam/cam.h> 54198389Smav#include <cam/cam_ccb.h> 55198389Smav#include <cam/cam_periph.h> 56198389Smav#include <cam/cam_xpt_periph.h> 57200218Smav#include <cam/cam_xpt_internal.h> 58198389Smav#include <cam/cam_sim.h> 59198389Smav 60198389Smav#include <cam/ata/ata_all.h> 61198389Smav 62198389Smav#ifdef _KERNEL 63198389Smav 64198389Smavtypedef enum { 65198389Smav PMP_STATE_NORMAL, 66198389Smav PMP_STATE_PORTS, 67199321Smav PMP_STATE_PRECONFIG, 68198389Smav PMP_STATE_RESET, 69198389Smav PMP_STATE_CONNECT, 70198389Smav PMP_STATE_CHECK, 71198389Smav PMP_STATE_CLEAR, 72199321Smav PMP_STATE_CONFIG, 73198389Smav PMP_STATE_SCAN 74198389Smav} pmp_state; 75198389Smav 76198389Smavtypedef enum { 77198389Smav PMP_FLAG_SCTX_INIT = 0x200 78198389Smav} pmp_flags; 79198389Smav 80198389Smavtypedef enum { 81198389Smav PMP_CCB_PROBE = 0x01, 82198389Smav} pmp_ccb_state; 83198389Smav 84198389Smav/* Offsets into our private area for storing information */ 85198389Smav#define ccb_state ppriv_field0 86198389Smav#define ccb_bp ppriv_ptr1 87198389Smav 88198389Smavstruct pmp_softc { 89198389Smav SLIST_ENTRY(pmp_softc) links; 90198389Smav pmp_state state; 91198389Smav pmp_flags flags; 92198389Smav uint32_t pm_pid; 93198389Smav uint32_t pm_prv; 94198389Smav int pm_ports; 95198389Smav int pm_step; 96198389Smav int pm_try; 97198389Smav int found; 98198708Smav int reset; 99198389Smav int frozen; 100198708Smav int restart; 101198389Smav union ccb saved_ccb; 102198389Smav struct task sysctl_task; 103198389Smav struct sysctl_ctx_list sysctl_ctx; 104198389Smav struct sysctl_oid *sysctl_tree; 105198389Smav}; 106198389Smav 107198389Smavstatic periph_init_t pmpinit; 108198389Smavstatic void pmpasync(void *callback_arg, u_int32_t code, 109198389Smav struct cam_path *path, void *arg); 110198389Smavstatic void pmpsysctlinit(void *context, int pending); 111198389Smavstatic periph_ctor_t pmpregister; 112198389Smavstatic periph_dtor_t pmpcleanup; 113198389Smavstatic periph_start_t pmpstart; 114198389Smavstatic periph_oninv_t pmponinvalidate; 115198389Smavstatic void pmpdone(struct cam_periph *periph, 116198389Smav union ccb *done_ccb); 117198389Smav 118198389Smav#ifndef PMP_DEFAULT_TIMEOUT 119198389Smav#define PMP_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 120198389Smav#endif 121198389Smav 122198389Smav#ifndef PMP_DEFAULT_RETRY 123198389Smav#define PMP_DEFAULT_RETRY 1 124198389Smav#endif 125198389Smav 126198389Smavstatic int pmp_retry_count = PMP_DEFAULT_RETRY; 127198389Smavstatic int pmp_default_timeout = PMP_DEFAULT_TIMEOUT; 128198389Smav 129198389SmavSYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD, 0, 130198389Smav "CAM Direct Access Disk driver"); 131198389SmavSYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RW, 132198389Smav &pmp_retry_count, 0, "Normal I/O retry count"); 133198389SmavTUNABLE_INT("kern.cam.pmp.retry_count", &pmp_retry_count); 134198389SmavSYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RW, 135198389Smav &pmp_default_timeout, 0, "Normal I/O timeout (in seconds)"); 136198389SmavTUNABLE_INT("kern.cam.pmp.default_timeout", &pmp_default_timeout); 137198389Smav 138198389Smavstatic struct periph_driver pmpdriver = 139198389Smav{ 140198389Smav pmpinit, "pmp", 141198708Smav TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0, 142198708Smav CAM_PERIPH_DRV_EARLY 143198389Smav}; 144198389Smav 145198389SmavPERIPHDRIVER_DECLARE(pmp, pmpdriver); 146198389Smav 147198389SmavMALLOC_DEFINE(M_ATPMP, "ata_pmp", "ata_pmp buffers"); 148198389Smav 149198389Smavstatic void 150198389Smavpmpinit(void) 151198389Smav{ 152198389Smav cam_status status; 153198389Smav 154198389Smav /* 155198389Smav * Install a global async callback. This callback will 156198389Smav * receive async callbacks like "new device found". 157198389Smav */ 158198389Smav status = xpt_register_async(AC_FOUND_DEVICE, pmpasync, NULL, NULL); 159198389Smav 160198389Smav if (status != CAM_REQ_CMP) { 161198389Smav printf("pmp: Failed to attach master async callback " 162198389Smav "due to status 0x%x!\n", status); 163198389Smav } 164198389Smav} 165198389Smav 166198389Smavstatic void 167198389Smavpmpfreeze(struct cam_periph *periph, int mask) 168198389Smav{ 169198389Smav struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 170198389Smav struct cam_path *dpath; 171198389Smav int i; 172198389Smav 173198389Smav mask &= ~softc->frozen; 174198389Smav for (i = 0; i < 15; i++) { 175198389Smav if ((mask & (1 << i)) == 0) 176198389Smav continue; 177198389Smav if (xpt_create_path(&dpath, periph, 178198389Smav xpt_path_path_id(periph->path), 179198389Smav i, 0) == CAM_REQ_CMP) { 180198389Smav softc->frozen |= (1 << i); 181200218Smav xpt_acquire_device(dpath->device); 182198389Smav cam_freeze_devq(dpath); 183198389Smav xpt_free_path(dpath); 184198389Smav } 185198389Smav } 186198389Smav} 187198389Smav 188198389Smavstatic void 189198389Smavpmprelease(struct cam_periph *periph, int mask) 190198389Smav{ 191198389Smav struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 192198389Smav struct cam_path *dpath; 193198389Smav int i; 194198389Smav 195198389Smav mask &= softc->frozen; 196198389Smav for (i = 0; i < 15; i++) { 197198389Smav if ((mask & (1 << i)) == 0) 198198389Smav continue; 199198389Smav if (xpt_create_path(&dpath, periph, 200198389Smav xpt_path_path_id(periph->path), 201198389Smav i, 0) == CAM_REQ_CMP) { 202198389Smav softc->frozen &= ~(1 << i); 203198389Smav cam_release_devq(dpath, 0, 0, 0, FALSE); 204200218Smav xpt_release_device(dpath->device); 205198389Smav xpt_free_path(dpath); 206198389Smav } 207198389Smav } 208198389Smav} 209198389Smav 210198389Smavstatic void 211198389Smavpmponinvalidate(struct cam_periph *periph) 212198389Smav{ 213198389Smav struct pmp_softc *softc; 214198389Smav struct cam_path *dpath; 215198389Smav int i; 216198389Smav 217198389Smav softc = (struct pmp_softc *)periph->softc; 218198389Smav 219198389Smav /* 220198389Smav * De-register any async callbacks. 221198389Smav */ 222198389Smav xpt_register_async(0, pmpasync, periph, periph->path); 223198389Smav 224198389Smav for (i = 0; i < 15; i++) { 225198389Smav if (xpt_create_path(&dpath, periph, 226198389Smav xpt_path_path_id(periph->path), 227198389Smav i, 0) == CAM_REQ_CMP) { 228198389Smav xpt_async(AC_LOST_DEVICE, dpath, NULL); 229198389Smav xpt_free_path(dpath); 230198389Smav } 231198389Smav } 232200218Smav pmprelease(periph, -1); 233198389Smav xpt_print(periph->path, "lost device\n"); 234198389Smav} 235198389Smav 236198389Smavstatic void 237198389Smavpmpcleanup(struct cam_periph *periph) 238198389Smav{ 239198389Smav struct pmp_softc *softc; 240198389Smav 241198389Smav softc = (struct pmp_softc *)periph->softc; 242198389Smav 243198389Smav xpt_print(periph->path, "removing device entry\n"); 244198389Smav cam_periph_unlock(periph); 245198389Smav 246198389Smav /* 247198389Smav * If we can't free the sysctl tree, oh well... 248198389Smav */ 249198389Smav if ((softc->flags & PMP_FLAG_SCTX_INIT) != 0 250198389Smav && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 251198389Smav xpt_print(periph->path, "can't remove sysctl context\n"); 252198389Smav } 253198389Smav 254198389Smav free(softc, M_DEVBUF); 255198389Smav cam_periph_lock(periph); 256198389Smav} 257198389Smav 258198389Smavstatic void 259198389Smavpmpasync(void *callback_arg, u_int32_t code, 260198389Smav struct cam_path *path, void *arg) 261198389Smav{ 262198389Smav struct cam_periph *periph; 263198389Smav struct pmp_softc *softc; 264198389Smav 265198389Smav periph = (struct cam_periph *)callback_arg; 266198389Smav switch (code) { 267198389Smav case AC_FOUND_DEVICE: 268198389Smav { 269198389Smav struct ccb_getdev *cgd; 270198389Smav cam_status status; 271198389Smav 272198389Smav cgd = (struct ccb_getdev *)arg; 273198389Smav if (cgd == NULL) 274198389Smav break; 275198389Smav 276198389Smav if (cgd->protocol != PROTO_SATAPM) 277198389Smav break; 278198389Smav 279198389Smav /* 280198389Smav * Allocate a peripheral instance for 281198389Smav * this device and start the probe 282198389Smav * process. 283198389Smav */ 284198389Smav status = cam_periph_alloc(pmpregister, pmponinvalidate, 285198389Smav pmpcleanup, pmpstart, 286198389Smav "pmp", CAM_PERIPH_BIO, 287198389Smav cgd->ccb_h.path, pmpasync, 288198389Smav AC_FOUND_DEVICE, cgd); 289198389Smav 290198389Smav if (status != CAM_REQ_CMP 291198389Smav && status != CAM_REQ_INPROG) 292198389Smav printf("pmpasync: Unable to attach to new device " 293198389Smav "due to status 0x%x\n", status); 294198389Smav break; 295198389Smav } 296198389Smav case AC_SCSI_AEN: 297198389Smav case AC_SENT_BDR: 298198389Smav case AC_BUS_RESET: 299198389Smav softc = (struct pmp_softc *)periph->softc; 300198389Smav cam_periph_async(periph, code, path, arg); 301198708Smav if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL && 302198708Smav softc->state != PMP_STATE_SCAN) 303198389Smav break; 304198708Smav if (softc->state != PMP_STATE_SCAN) 305198708Smav pmpfreeze(periph, softc->found); 306198708Smav else 307198708Smav pmpfreeze(periph, softc->found & ~(1 << softc->pm_step)); 308198389Smav if (code == AC_SENT_BDR || code == AC_BUS_RESET) 309198389Smav softc->found = 0; /* We have to reset everything. */ 310198708Smav if (softc->state == PMP_STATE_NORMAL) { 311198708Smav softc->state = PMP_STATE_PORTS; 312198708Smav cam_periph_acquire(periph); 313198708Smav xpt_schedule(periph, CAM_PRIORITY_BUS); 314198708Smav } else 315198708Smav softc->restart = 1; 316198389Smav break; 317198389Smav default: 318198389Smav cam_periph_async(periph, code, path, arg); 319198389Smav break; 320198389Smav } 321198389Smav} 322198389Smav 323198389Smavstatic void 324198389Smavpmpsysctlinit(void *context, int pending) 325198389Smav{ 326198389Smav struct cam_periph *periph; 327198389Smav struct pmp_softc *softc; 328198389Smav char tmpstr[80], tmpstr2[80]; 329198389Smav 330198389Smav periph = (struct cam_periph *)context; 331198389Smav if (cam_periph_acquire(periph) != CAM_REQ_CMP) 332198389Smav return; 333198389Smav 334198389Smav softc = (struct pmp_softc *)periph->softc; 335198389Smav snprintf(tmpstr, sizeof(tmpstr), "CAM PMP unit %d", periph->unit_number); 336198389Smav snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 337198389Smav 338198389Smav sysctl_ctx_init(&softc->sysctl_ctx); 339198389Smav softc->flags |= PMP_FLAG_SCTX_INIT; 340198389Smav softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 341198389Smav SYSCTL_STATIC_CHILDREN(_kern_cam_pmp), OID_AUTO, tmpstr2, 342198389Smav CTLFLAG_RD, 0, tmpstr); 343198389Smav if (softc->sysctl_tree == NULL) { 344198389Smav printf("pmpsysctlinit: unable to allocate sysctl tree\n"); 345198389Smav cam_periph_release(periph); 346198389Smav return; 347198389Smav } 348198389Smav 349198389Smav cam_periph_release(periph); 350198389Smav} 351198389Smav 352198389Smavstatic cam_status 353198389Smavpmpregister(struct cam_periph *periph, void *arg) 354198389Smav{ 355198389Smav struct pmp_softc *softc; 356198389Smav struct ccb_pathinq cpi; 357198389Smav struct ccb_getdev *cgd; 358198389Smav 359198389Smav cgd = (struct ccb_getdev *)arg; 360198389Smav if (periph == NULL) { 361198389Smav printf("pmpregister: periph was NULL!!\n"); 362198389Smav return(CAM_REQ_CMP_ERR); 363198389Smav } 364198389Smav 365198389Smav if (cgd == NULL) { 366198389Smav printf("pmpregister: no getdev CCB, can't register device\n"); 367198389Smav return(CAM_REQ_CMP_ERR); 368198389Smav } 369198389Smav 370198389Smav softc = (struct pmp_softc *)malloc(sizeof(*softc), M_DEVBUF, 371198389Smav M_NOWAIT|M_ZERO); 372198389Smav 373198389Smav if (softc == NULL) { 374198389Smav printf("pmpregister: Unable to probe new device. " 375198389Smav "Unable to allocate softc\n"); 376198389Smav return(CAM_REQ_CMP_ERR); 377198389Smav } 378198389Smav periph->softc = softc; 379198389Smav 380198389Smav softc->state = PMP_STATE_PORTS; 381198389Smav softc->pm_pid = ((uint32_t *)&cgd->ident_data)[0]; 382198389Smav softc->pm_prv = ((uint32_t *)&cgd->ident_data)[1]; 383198389Smav 384198389Smav /* Check if the SIM does not want queued commands */ 385198389Smav bzero(&cpi, sizeof(cpi)); 386198389Smav xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 387198389Smav cpi.ccb_h.func_code = XPT_PATH_INQ; 388198389Smav xpt_action((union ccb *)&cpi); 389198389Smav 390198389Smav TASK_INIT(&softc->sysctl_task, 0, pmpsysctlinit, periph); 391198389Smav 392198389Smav xpt_announce_periph(periph, NULL); 393198389Smav 394198389Smav /* 395198389Smav * Add async callbacks for bus reset and 396198389Smav * bus device reset calls. I don't bother 397198389Smav * checking if this fails as, in most cases, 398198389Smav * the system will function just fine without 399198389Smav * them and the only alternative would be to 400198389Smav * not attach the device on failure. 401198389Smav */ 402198389Smav xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 403198389Smav AC_SCSI_AEN, pmpasync, periph, periph->path); 404198389Smav 405198389Smav /* 406198389Smav * Take an exclusive refcount on the periph while pmpstart is called 407198389Smav * to finish the probe. The reference will be dropped in pmpdone at 408198389Smav * the end of probe. 409198389Smav */ 410198389Smav (void)cam_periph_acquire(periph); 411198708Smav xpt_schedule(periph, CAM_PRIORITY_BUS); 412198389Smav 413198389Smav return(CAM_REQ_CMP); 414198389Smav} 415198389Smav 416198389Smavstatic void 417198389Smavpmpstart(struct cam_periph *periph, union ccb *start_ccb) 418198389Smav{ 419198389Smav struct ccb_ataio *ataio; 420198389Smav struct pmp_softc *softc; 421198389Smav 422198389Smav softc = (struct pmp_softc *)periph->softc; 423198389Smav ataio = &start_ccb->ataio; 424198708Smav 425198708Smav if (softc->restart) { 426198708Smav softc->restart = 0; 427198708Smav softc->state = PMP_STATE_PORTS; 428198708Smav } 429198389Smav 430198389Smav switch (softc->state) { 431198389Smav case PMP_STATE_PORTS: 432198389Smav cam_fill_ataio(ataio, 433198389Smav pmp_retry_count, 434198389Smav pmpdone, 435198389Smav /*flags*/CAM_DIR_NONE, 436198389Smav 0, 437198389Smav /*data_ptr*/NULL, 438198389Smav /*dxfer_len*/0, 439198389Smav pmp_default_timeout * 1000); 440198389Smav ata_pm_read_cmd(ataio, 2, 15); 441198389Smav break; 442199321Smav case PMP_STATE_PRECONFIG: 443198389Smav cam_fill_ataio(ataio, 444198389Smav pmp_retry_count, 445198389Smav pmpdone, 446198389Smav /*flags*/CAM_DIR_NONE, 447198389Smav 0, 448198389Smav /*data_ptr*/NULL, 449198389Smav /*dxfer_len*/0, 450198389Smav pmp_default_timeout * 1000); 451199321Smav ata_pm_write_cmd(ataio, 0x60, 15, 0x0); 452198389Smav break; 453198389Smav case PMP_STATE_RESET: 454198389Smav cam_fill_ataio(ataio, 455198389Smav pmp_retry_count, 456198389Smav pmpdone, 457198389Smav /*flags*/CAM_DIR_NONE, 458198389Smav 0, 459198389Smav /*data_ptr*/NULL, 460198389Smav /*dxfer_len*/0, 461198389Smav pmp_default_timeout * 1000); 462198389Smav ata_pm_write_cmd(ataio, 2, softc->pm_step, 463198389Smav (softc->found & (1 << softc->pm_step)) ? 0 : 1); 464198389Smav break; 465198389Smav case PMP_STATE_CONNECT: 466198389Smav cam_fill_ataio(ataio, 467198389Smav pmp_retry_count, 468198389Smav pmpdone, 469198389Smav /*flags*/CAM_DIR_NONE, 470198389Smav 0, 471198389Smav /*data_ptr*/NULL, 472198389Smav /*dxfer_len*/0, 473198389Smav pmp_default_timeout * 1000); 474198389Smav ata_pm_write_cmd(ataio, 2, softc->pm_step, 0); 475198389Smav break; 476198389Smav case PMP_STATE_CHECK: 477198389Smav cam_fill_ataio(ataio, 478198389Smav pmp_retry_count, 479198389Smav pmpdone, 480198389Smav /*flags*/CAM_DIR_NONE, 481198389Smav 0, 482198389Smav /*data_ptr*/NULL, 483198389Smav /*dxfer_len*/0, 484198389Smav pmp_default_timeout * 1000); 485198389Smav ata_pm_read_cmd(ataio, 0, softc->pm_step); 486198389Smav break; 487198389Smav case PMP_STATE_CLEAR: 488198708Smav softc->reset = 0; 489198389Smav cam_fill_ataio(ataio, 490198389Smav pmp_retry_count, 491198389Smav pmpdone, 492198389Smav /*flags*/CAM_DIR_NONE, 493198389Smav 0, 494198389Smav /*data_ptr*/NULL, 495198389Smav /*dxfer_len*/0, 496198389Smav pmp_default_timeout * 1000); 497198389Smav ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF); 498198389Smav break; 499199321Smav case PMP_STATE_CONFIG: 500199321Smav cam_fill_ataio(ataio, 501199321Smav pmp_retry_count, 502199321Smav pmpdone, 503199321Smav /*flags*/CAM_DIR_NONE, 504199321Smav 0, 505199321Smav /*data_ptr*/NULL, 506199321Smav /*dxfer_len*/0, 507199321Smav pmp_default_timeout * 1000); 508199321Smav ata_pm_write_cmd(ataio, 0x60, 15, 0xf); 509199321Smav break; 510198389Smav default: 511198389Smav break; 512198389Smav } 513198389Smav xpt_action(start_ccb); 514198389Smav} 515198389Smav 516198389Smavstatic void 517198389Smavpmpdone(struct cam_periph *periph, union ccb *done_ccb) 518198389Smav{ 519199747Smav struct ccb_trans_settings cts; 520198389Smav struct pmp_softc *softc; 521198389Smav struct ccb_ataio *ataio; 522198389Smav union ccb *work_ccb; 523198389Smav struct cam_path *path, *dpath; 524198708Smav u_int32_t priority, res; 525198389Smav 526198389Smav softc = (struct pmp_softc *)periph->softc; 527198389Smav ataio = &done_ccb->ataio; 528198389Smav 529198389Smav CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("pmpdone\n")); 530198389Smav 531198389Smav path = done_ccb->ccb_h.path; 532198389Smav priority = done_ccb->ccb_h.pinfo.priority; 533198389Smav 534198708Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 535198708Smav if (cam_periph_error(done_ccb, 0, 0, 536198708Smav &softc->saved_ccb) == ERESTART) { 537198389Smav return; 538198389Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 539198708Smav cam_release_devq(done_ccb->ccb_h.path, 540198708Smav /*relsim_flags*/0, 541198708Smav /*reduction*/0, 542198708Smav /*timeout*/0, 543198708Smav /*getcount_only*/0); 544198389Smav } 545198708Smav goto done; 546198708Smav } 547198708Smav 548198708Smav if (softc->restart) { 549198708Smav softc->restart = 0; 550198708Smav if (softc->state == PMP_STATE_SCAN) { 551198708Smav pmpfreeze(periph, 1 << softc->pm_step); 552198708Smav work_ccb = done_ccb; 553198708Smav done_ccb = (union ccb*)work_ccb->ccb_h.ppriv_ptr0; 554198708Smav /* Free the current request path- we're done with it. */ 555198708Smav xpt_free_path(work_ccb->ccb_h.path); 556198708Smav xpt_free_ccb(work_ccb); 557198708Smav } 558198389Smav xpt_release_ccb(done_ccb); 559198708Smav softc->state = PMP_STATE_PORTS; 560198708Smav xpt_schedule(periph, priority); 561198708Smav return; 562198708Smav } 563198708Smav 564198708Smav switch (softc->state) { 565198708Smav case PMP_STATE_PORTS: 566198708Smav softc->pm_ports = (done_ccb->ataio.res.lba_high << 24) + 567198708Smav (done_ccb->ataio.res.lba_mid << 16) + 568198708Smav (done_ccb->ataio.res.lba_low << 8) + 569198708Smav done_ccb->ataio.res.sector_count; 570199321Smav /* This PMP declares 6 ports, while only 5 of them are real. 571198708Smav * Port 5 is enclosure management bridge port, which has implementation 572198708Smav * problems, causing probe faults. Hide it for now. */ 573198708Smav if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6) 574198708Smav softc->pm_ports = 5; 575199321Smav /* This PMP declares 7 ports, while only 5 of them are real. 576198708Smav * Port 5 is some fake "Config Disk" with 640 sectors size, 577198708Smav * port 6 is enclosure management bridge port. 578198708Smav * Both fake ports has implementation problems, causing 579198708Smav * probe faults. Hide them for now. */ 580198708Smav if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7) 581198708Smav softc->pm_ports = 5; 582199321Smav /* These PMPs declare one more port then actually have, 583199321Smav * for configuration purposes. Hide it for now. */ 584199321Smav if (softc->pm_pid == 0x57231095 || softc->pm_pid == 0x57331095 || 585199321Smav softc->pm_pid == 0x57341095 || softc->pm_pid == 0x57441095) 586199321Smav softc->pm_ports--; 587200218Smav printf("%s%d: %d fan-out ports\n", 588200218Smav periph->periph_name, periph->unit_number, 589200218Smav softc->pm_ports); 590199321Smav softc->state = PMP_STATE_PRECONFIG; 591198708Smav xpt_release_ccb(done_ccb); 592198708Smav xpt_schedule(periph, priority); 593198708Smav return; 594199321Smav case PMP_STATE_PRECONFIG: 595198708Smav softc->pm_step = 0; 596198708Smav softc->state = PMP_STATE_RESET; 597198708Smav softc->reset |= ~softc->found; 598198389Smav xpt_release_ccb(done_ccb); 599198708Smav xpt_schedule(periph, priority); 600198708Smav return; 601198389Smav case PMP_STATE_RESET: 602198708Smav softc->pm_step++; 603198708Smav if (softc->pm_step >= softc->pm_ports) { 604198708Smav softc->pm_step = 0; 605198708Smav cam_freeze_devq(periph->path); 606198708Smav cam_release_devq(periph->path, 607198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 608198708Smav /*reduction*/0, 609198708Smav /*timeout*/5, 610198708Smav /*getcount_only*/0); 611198708Smav softc->state = PMP_STATE_CONNECT; 612198389Smav } 613198389Smav xpt_release_ccb(done_ccb); 614198708Smav xpt_schedule(periph, priority); 615198708Smav return; 616198389Smav case PMP_STATE_CONNECT: 617198708Smav softc->pm_step++; 618198708Smav if (softc->pm_step >= softc->pm_ports) { 619198708Smav softc->pm_step = 0; 620198708Smav softc->pm_try = 0; 621198708Smav cam_freeze_devq(periph->path); 622198708Smav cam_release_devq(periph->path, 623198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 624198708Smav /*reduction*/0, 625198708Smav /*timeout*/10, 626198708Smav /*getcount_only*/0); 627198708Smav softc->state = PMP_STATE_CHECK; 628198389Smav } 629198389Smav xpt_release_ccb(done_ccb); 630198708Smav xpt_schedule(periph, priority); 631198708Smav return; 632198389Smav case PMP_STATE_CHECK: 633198708Smav res = (done_ccb->ataio.res.lba_high << 24) + 634198708Smav (done_ccb->ataio.res.lba_mid << 16) + 635198708Smav (done_ccb->ataio.res.lba_low << 8) + 636198708Smav done_ccb->ataio.res.sector_count; 637198708Smav if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) { 638200218Smav if (bootverbose) { 639200218Smav printf("%s%d: port %d status: %08x\n", 640200218Smav periph->periph_name, periph->unit_number, 641200218Smav softc->pm_step, res); 642200218Smav } 643199747Smav /* Report device speed. */ 644199747Smav if (xpt_create_path(&dpath, periph, 645199747Smav xpt_path_path_id(periph->path), 646199747Smav softc->pm_step, 0) == CAM_REQ_CMP) { 647199747Smav bzero(&cts, sizeof(cts)); 648199747Smav xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NORMAL); 649199747Smav cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 650199747Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 651199747Smav cts.xport_specific.sata.revision = (res & 0x0f0) >> 4; 652199747Smav cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION; 653199747Smav xpt_action((union ccb *)&cts); 654199747Smav xpt_free_path(dpath); 655199747Smav } 656198708Smav softc->found |= (1 << softc->pm_step); 657198708Smav softc->pm_step++; 658198708Smav } else { 659198708Smav if (softc->pm_try < 10) { 660198708Smav cam_freeze_devq(periph->path); 661198708Smav cam_release_devq(periph->path, 662198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 663198708Smav /*reduction*/0, 664198708Smav /*timeout*/10, 665198708Smav /*getcount_only*/0); 666198708Smav softc->pm_try++; 667198708Smav } else { 668200218Smav if (bootverbose) { 669200218Smav printf("%s%d: port %d status: %08x\n", 670200218Smav periph->periph_name, periph->unit_number, 671200218Smav softc->pm_step, res); 672200218Smav } 673198708Smav softc->found &= ~(1 << softc->pm_step); 674198708Smav if (xpt_create_path(&dpath, periph, 675198708Smav done_ccb->ccb_h.path_id, 676198708Smav softc->pm_step, 0) == CAM_REQ_CMP) { 677198708Smav xpt_async(AC_LOST_DEVICE, dpath, NULL); 678198708Smav xpt_free_path(dpath); 679198708Smav } 680198389Smav softc->pm_step++; 681198389Smav } 682198708Smav } 683198708Smav if (softc->pm_step >= softc->pm_ports) { 684198708Smav if (softc->reset & softc->found) { 685198708Smav cam_freeze_devq(periph->path); 686198708Smav cam_release_devq(periph->path, 687198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 688198708Smav /*reduction*/0, 689198708Smav /*timeout*/1000, 690198708Smav /*getcount_only*/0); 691198389Smav } 692198708Smav softc->state = PMP_STATE_CLEAR; 693198708Smav softc->pm_step = 0; 694198389Smav } 695198389Smav xpt_release_ccb(done_ccb); 696198708Smav xpt_schedule(periph, priority); 697198708Smav return; 698198389Smav case PMP_STATE_CLEAR: 699198708Smav softc->pm_step++; 700199321Smav if (softc->pm_step >= softc->pm_ports) { 701199321Smav softc->state = PMP_STATE_CONFIG; 702198708Smav softc->pm_step = 0; 703199321Smav } 704199321Smav xpt_release_ccb(done_ccb); 705199321Smav xpt_schedule(periph, priority); 706199321Smav return; 707199321Smav case PMP_STATE_CONFIG: 708199321Smav if (softc->found) { 709199321Smav softc->pm_step = 0; 710198708Smav softc->state = PMP_STATE_SCAN; 711198708Smav work_ccb = xpt_alloc_ccb_nowait(); 712198708Smav if (work_ccb != NULL) 713198708Smav goto do_scan; 714198708Smav xpt_release_ccb(done_ccb); 715198389Smav } 716198389Smav break; 717198389Smav case PMP_STATE_SCAN: 718198389Smav work_ccb = done_ccb; 719198389Smav done_ccb = (union ccb*)work_ccb->ccb_h.ppriv_ptr0; 720198389Smav /* Free the current request path- we're done with it. */ 721198389Smav xpt_free_path(work_ccb->ccb_h.path); 722198389Smav softc->pm_step++; 723198389Smavdo_scan: 724198389Smav while (softc->pm_step < softc->pm_ports && 725198389Smav (softc->found & (1 << softc->pm_step)) == 0) { 726198389Smav softc->pm_step++; 727198389Smav } 728198389Smav if (softc->pm_step >= softc->pm_ports) { 729198389Smav xpt_free_ccb(work_ccb); 730198389Smav break; 731198389Smav } 732198389Smav if (xpt_create_path(&dpath, periph, 733198389Smav done_ccb->ccb_h.path_id, 734198389Smav softc->pm_step, 0) != CAM_REQ_CMP) { 735198389Smav printf("pmpdone: xpt_create_path failed" 736198389Smav ", bus scan halted\n"); 737198389Smav xpt_free_ccb(work_ccb); 738198389Smav break; 739198389Smav } 740198389Smav xpt_setup_ccb(&work_ccb->ccb_h, dpath, 741198389Smav done_ccb->ccb_h.pinfo.priority); 742198389Smav work_ccb->ccb_h.func_code = XPT_SCAN_LUN; 743198389Smav work_ccb->ccb_h.cbfcnp = pmpdone; 744198389Smav work_ccb->ccb_h.ppriv_ptr0 = done_ccb; 745198389Smav work_ccb->crcn.flags = done_ccb->crcn.flags; 746198389Smav xpt_action(work_ccb); 747198389Smav pmprelease(periph, 1 << softc->pm_step); 748198389Smav return; 749198389Smav default: 750198389Smav break; 751198389Smav } 752198708Smavdone: 753198708Smav xpt_release_ccb(done_ccb); 754198389Smav softc->state = PMP_STATE_NORMAL; 755198389Smav pmprelease(periph, -1); 756198389Smav cam_periph_release_locked(periph); 757198389Smav} 758198389Smav 759198389Smav#endif /* _KERNEL */ 760