1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Utility DCD configuration routines. 31 */ 32 33 #include <sys/dada/dada.h> 34 #include <sys/modctl.h> 35 36 extern struct mod_ops mod_miscops; 37 38 static struct modlmisc modlmisc = { 39 &mod_miscops, /* Type of module */ 40 " ATA Bus Utility Routines" 41 }; 42 43 static struct modlinkage modlinkage = { 44 MODREV_1, (void *)&modlmisc, NULL 45 }; 46 47 48 49 static int dcd_test(struct dcd_pkt *); 50 void makecommand(struct dcd_pkt *, int, uchar_t, uint32_t, 51 uchar_t, uint32_t, uchar_t, uchar_t); 52 53 int 54 _init() 55 { 56 57 (void) dcd_initialize_hba_interface(); 58 59 return (mod_install(&modlinkage)); 60 } 61 62 63 /* 64 * There is no _fini() routine because this module is never unloaded. 65 */ 66 int 67 _info(modinfop) 68 struct modinfo *modinfop; 69 { 70 71 return (mod_info(&modlinkage, modinfop)); 72 } 73 74 /* 75 * The implementation of dcd_probe allows a particular HBA to intercept the call 76 * for any post or pre-processing it may need. The default, if the HBA does not 77 * override it, is to call dcd_hba_probe. 78 */ 79 int 80 dcd_probe(struct dcd_device *devp, int (*callback)()) 81 { 82 dcd_hba_tran_t *hba_tran = devp->dcd_address->a_hba_tran; 83 84 if (hba_tran->tran_tgt_probe != NULL) { 85 return ((*hba_tran->tran_tgt_probe)(devp, callback)); 86 } else { 87 return (dcd_hba_probe(devp, callback)); 88 } 89 } 90 91 /* 92 * Undo the dcd_probe 93 */ 94 void 95 dcd_unprobe(struct dcd_device *devp) 96 { 97 if (devp->dcd_ident) { 98 kmem_free((caddr_t)devp->dcd_ident, SUN_IDENTSIZE); 99 devp->dcd_ident = (struct dcd_identify *)NULL; 100 } 101 } 102 103 #define ROUTE (devp->dcd_address) 104 105 int 106 dcd_hba_probe(struct dcd_device *devp, int (*callback)()) 107 { 108 109 struct dcd_pkt *ident_pkt = NULL; 110 int rval = DCDPROBE_NOMEM; 111 struct buf *ident_bp = NULL; 112 int (*cb_flag)(); 113 114 if (devp->dcd_ident == NULL) { 115 #ifdef DEBUG1 116 printf("Dcd_ident is NULL\n"); 117 #endif 118 119 devp->dcd_ident = (struct dcd_identify *) 120 kmem_alloc(SUN_IDENTSIZE, ((callback == SLEEP_FUNC)? 121 KM_SLEEP : KM_NOSLEEP)); 122 if (devp->dcd_ident == NULL) { 123 goto out; 124 } 125 } 126 127 if (callback != SLEEP_FUNC && callback != NULL_FUNC) { 128 cb_flag = NULL_FUNC; 129 } else { 130 cb_flag = callback; 131 } 132 133 ident_bp = dcd_alloc_consistent_buf(ROUTE, (struct buf *)NULL, 134 (uint_t)SUN_IDENTSIZE, B_READ, cb_flag, NULL); 135 if (ident_bp == NULL) { 136 goto out; 137 } 138 139 ident_pkt = dcd_init_pkt(ROUTE, (struct dcd_pkt *)NULL, 140 ident_bp, sizeof (struct dcd_cmd), 2, 0, 141 PKT_CONSISTENT, 142 callback, NULL); 143 144 if (ident_pkt == NULL) { 145 if (ident_bp->b_error == 0) 146 rval = DCDPROBE_NOMEM_CB; 147 goto out; 148 } 149 150 bp_mapin(ident_bp); 151 152 bzero((caddr_t)devp->dcd_ident, SUN_IDENTSIZE); 153 154 makecommand(ident_pkt, FLAG_NOINTR, IDENTIFY, 0, ADD_LBA_MODE, 155 SUN_IDENTSIZE, DATA_READ, 0); 156 157 /* 158 * The first identify will tell us whether the target responded 159 * or not. 160 */ 161 162 if (dcd_test(ident_pkt) < 0) { 163 #ifdef DEBUG1 164 printf("dcd_test: failed\n"); 165 #endif 166 if (ident_pkt->pkt_reason == CMD_INCOMPLETE) { 167 rval = DCDPROBE_NORESP; 168 goto out; 169 } else { 170 /* 171 * retry one more time 172 */ 173 if (dcd_test(ident_pkt) < 0) { 174 rval = DCDPROBE_FAILURE; 175 goto out; 176 } 177 } 178 } 179 180 #ifdef DEBUG1 181 printf("Pkt reason %x, scsbp %x\n", ident_pkt->pkt_reason, 182 *ident_pkt->pkt_scbp); 183 #endif 184 /* 185 * If we are lucky, this identify succeeded 186 */ 187 if ((ident_pkt->pkt_reason == CMD_CMPLT) && 188 (((*ident_pkt->pkt_scbp) & STATUS_ATA_MASK) == 0)) { 189 goto done; 190 } 191 192 /* 193 * the second inquiry, allows the host adapters to try again. 194 */ 195 if (dcd_test(ident_pkt) < 0) { 196 if (ident_pkt->pkt_reason == CMD_INCOMPLETE) 197 rval = DCDPROBE_NORESP; 198 else 199 rval = DCDPROBE_FAILURE; 200 goto out; 201 } 202 203 /* 204 * At this point we are guarenteed that something responded 205 * to this target. We don't know yest what kind of device it is. 206 */ 207 208 if (dcd_test(ident_pkt) < 0) { 209 rval = DCDPROBE_FAILURE; 210 goto out; 211 } 212 213 done: 214 /* 215 * If we got no error then receive the indentify data, 216 */ 217 if ((ident_pkt->pkt_state & STATE_XFERRED_DATA) == 0 && 218 ident_pkt->pkt_resid > 0) { 219 rval = DCDPROBE_NONCCS; 220 } else { 221 bcopy((caddr_t)ident_bp->b_un.b_addr, 222 (caddr_t)devp->dcd_ident, SUN_IDENTSIZE); 223 rval = DCDPROBE_EXISTS; 224 } 225 226 out: 227 if (ident_pkt) { 228 dcd_destroy_pkt(ident_pkt); 229 } 230 if (ident_bp) { 231 dcd_free_consistent_buf(ident_bp); 232 } 233 return (rval); 234 } 235 236 237 static int 238 dcd_test(struct dcd_pkt *pkt) 239 { 240 241 int rval = -1; 242 243 pkt->pkt_flags |= FLAG_NOINTR; 244 pkt->pkt_time = DCD_POLL_TIMEOUT; 245 246 #ifdef DEBUG1 247 printf("flags %x: timeout %x\n", pkt->pkt_flags, pkt->pkt_time); 248 #endif 249 250 if (dcd_transport(pkt) != TRAN_ACCEPT) { 251 goto error; 252 } else if (pkt->pkt_reason == CMD_INCOMPLETE && 253 pkt->pkt_state == 0) { 254 goto error; 255 } else if (pkt->pkt_reason != CMD_CMPLT) { 256 goto error; 257 } else if (((*pkt->pkt_scbp) & STATUS_ATA_MASK) == STATUS_ATA_BUSY) { 258 rval = 0; 259 } else { 260 rval = 0; 261 } 262 error: 263 #ifdef DEBUG1 264 printf("dcd_test: rval is %x\n", rval); 265 #endif 266 267 return (rval); 268 } 269 270 void 271 makecommand(struct dcd_pkt *pkt, 272 int flags, 273 uchar_t command, 274 uint32_t block, 275 uchar_t address_mode, 276 uint32_t size, 277 uchar_t direction, 278 uchar_t features) 279 { 280 281 struct dcd_cmd *cdbp = (struct dcd_cmd *)pkt->pkt_cdbp; 282 283 cdbp->cmd = command; 284 cdbp->sector_num.lba_num = block; 285 cdbp->address_mode = address_mode; 286 cdbp->direction = direction; 287 cdbp->size = size; /* Size in bytes */ 288 cdbp->features = features; 289 290 pkt->pkt_flags = flags; 291 #ifdef DEBUG1 292 printf("pkt flags set in dada %x\n", pkt->pkt_flags); 293 294 printf("command %x, flags %x, block %x, address_mode %x, size %x\n", 295 command, flags, block, address_mode, size); 296 #endif 297 298 299 } 300